How to asaign lambda funcion in unordered_map with cpp? - c++

Currently trying to learn c++, and I'm trying to make a "hunt the wumpus" application to help me learn. I am having trouble assigning a lambda function to an unordered_map in C++. My IDE is giving me the error
"Parameter type mismatch: Incompatible pointer types 'node *const' and 'node ()(node *)'"
#include <iostream>
#include <string>
#include <unordered_map>
class node{
public:
int title;
node *adj[8];
std::string desc;
}
...
bool shoot(node *player){
std::unordered_map<std::string, node*> adjLambda; //lambda to return *left, *up, etc
for (int i; i < 8; i++){
if (player->adj[i]->title != player->title){ //empty adjacencies points towards self
adjLambda.insert(std::pair <std::string, node*> (std::to_string(player->adj[i]->title), [](node *n) { return n->adj[i];}));
}
}
}

You can include <functional> and then store the value as a std::function:
void shoot(node *player){
std::unordered_map<std::string, std::function<node*(node*)>> adjLambda; //lambda to return *left, *up, etc
for(int i{}; i < 8; i++){
if(player->adj[i]->title != player->title){ //empty adjacencies points towards self
adjLambda.insert( // insert into the unordered map
std::pair< // pair to be inserted
std::string, // key is a string
std::function< // map entry is a function
node*(node*) // function takes a node pointer and returns a node pointer
>
>(
std::to_string(player->adj[i]->title), // create a string to use as the key
[i](node *n) { return n->adj[i]; } // lambda that takes a node pointer and returns another
)
);
}
}
}

Related

C++ how to work with a linked list whose datatype is a pair?

I have a linked list called:
LinkedList <std::pair <std::string, (class called Process)>> thelist;
So, the exact declaration is:
LinkedList <std::pair <std::string, Process>> thelist;
Suppose I have stored a series of Process inside thelist, and the first datatype of the pair (i.e. string) identifies what category of process it is. Let's say if the category is Stop, it stores the Process inside the list under Stop, and if the category is Resume: the Process is stored under Resume and so on.
My problem is, I am struggling to access the two types of data in pair for other methods I am required to implement. For example: I need to implement a method called Count_category( string category) that will count the number of Process inside the given category, but I can't figure out how to do so, as I don't know how to access the first datatype. I have figured out so far it can be accessed by doing like class.first and class.second, but can't figure out how I would use it in my case.
Help!!
I am including my linkedlist.hpp, if you need my class object that is used in the pair, let me know.
#ifndef LINKED_LIST_
#define LINKED_LIST_
#include <utility> //for swap
#include <exception>
#include "Node.hpp"
template<typename T>
class LinkedList
{
private:
Node<T>* head; // Pointer to first node in the chain;
// (contains the first entry in the list)
int count; // Current count of list items
// Locates a specified node in this linked list.
// #pre position is the number of the desired node;
// position >= 1 and position <= itemCount.
// #post The node is found and a pointer to it is returned.
// #param position The number of the node to locate.
// #return A pointer to the node at the given position.
Node<T>* getNodeAt(int position) const;
void swap( LinkedList& lhs, LinkedList& rhs );
public:
LinkedList();
LinkedList(const LinkedList<T>& rhs);
virtual ~LinkedList();
LinkedList& operator=( LinkedList rhs );
bool isEmpty() const;
int get_count() const;
bool insert(int newPosition, const T& newEntry);
bool remove(int position);
void clear();
T getEntry(int position) const;
T replace(int position, const T& newEntry);
}; // end LinkedList
#endif
``````````````````````````````````````````````````````````````
##This is where I'm stuck: (it's in a different class called PManager that uses this Linked List);##
``````````````````````````````````````````````````````````````````
int PManager::count_category(std::string category) const
{
int count = 0;
for (int i = 1; i <= theList.get_count(); i++)
{
if (category == (this is where I need to access the category from the pair)
{
count++;
}
}
```````````````````````````````````````````````````````
Suppose you get an element (or a reference to it) from LinkedList:
std::pair <std::string, Process> const& elem = llist.getEntry(0);
// now elem.first is a std::string
elem is a (reference to) std::pair <std::string, Process>. You can then use elem.first (which is a std::string) and elem.second (which is a Process).
Note that getEntry is inefficient: it returns a copy of the element in the list.
Whith the interface you present it would be something like:
int main()
{
LinkedList< std::pair< std::string, Process > > list;
//... put in some data
// count all elements in a given category
std::string what{"Stop"};
int found = 0;
for ( int count = 0; count < list.get_count(); count++ )
{
std::pair< std::string, Process > element = list.getEntry( count );
if ( element.first == what )
{
found++;
}
}
std::cout << "Found " << found << " elements in category " << what << std::endl;
}
You LinkedList class has a very bad design because of:
no iterators are present, so it can't be used with standard algorithms
getter method returns a full copy,inefficient, no change of data possible
access methods must iterate through all elements which is absolute unacceptable
constructors did not allow to put data in
no move construction
insert only with given position, needs a lot of iterations, inefficient and complex to handle
no front() and back() operators
.... a lot more
If you use a stl compliant interface for your linked list, you can implement the functionality much easier. Only as an example for C++20:
#include <ranges>
#include <algorithm>
#include <list>
#include <iostream>
class Process{};
int main()
{
std::list< std::pair< std::string, Process > > l{ { "Stop", {} }, {"Resume",{}},{"Stop",{}}};
std::string what{"Resume"};
int found = std::ranges::count_if( l | std::views::keys , [&what]( const auto&s ){return s==what;} );
std::cout << "Found " << found << " elements in category " << what << std::endl;
}

Accessing a structure through another structure member in C++

I'm trying to access a structure using another structure. From the below program, element is the member of Node. At this line " temp->element *e_temp;", I couldn't link the "element" member of Node to the "elements" structure object.
compile error says "'e_temp' was not declared in this scope". What am I missing?
#include <vector>
#include <cstdlib>
using namespace std;
typedef struct Elements
{
int data;
struct Elements *next;
}elements;
typedef struct Node
{
int sno;
elements *element;
struct Node *next;
}node;
void add(int sno, vector<int> a)
{
node *temp;
temp = new node;
temp->element *e_temp;
e_temp = new elements;
temp->sno = sno;
while(a.size())
{
temp->e_temp->data = a[0];
temp->e_temp = temp->e_temp->next;
a.erase(a.begin());
}
}
int main()
{
vector<int> a{1,2,3};
int sno = 1;
add(sno, a);
return 0;
}
If you're just looking to declare a local you can do auto e_temp = new elements but what i think you want is this for that line temp->element = new elements;
and then follow up with the rest of your code to reference temp's element instead of e_temp.
temp->element->data = a[0];
temp->element = temp->element->next
Also, i'd try to get out the habit of using new and use std::shared_ptr and std::unique_ptr instead.
The correct declaration for e_temp is
elements * e_temp;
but e_temp is not use of any part of your code.

How to sort the map based on value in c++ using stl?

struct node{
int index;
int count;
};
map<int,struct node *> m1;
bool compare(struct node* a, struct node* b) {
if(a->count>b->count)
return 1;
if(a->count==b->count && a->index<b->index)
return 1;
return 0;
}
Can i sort the map based on greater count value and if count is equal then based on lower index value?
A way is to push all the values in vector and perform sort. Is there any other way by which sorting can be done using priority queue as below?
priority_queue<pair<int,struct node *>, vector<int,struct node *>, compare> pq(m1.begin(),m1.end());
I have provided the compare function above.
You could try using Boost Multi-Index. One index provides map access, the other provides ordered iterator access.
Solution using priority_queue
class compare {
public:
bool operator()(pair<int,struct node *> a, pair<int,struct node *> b) {
if(a.second->count>b.second->count)
return 0;
if(a.second->count==b.second->count && a.second->index<b.second->index)
return 0;
return 1;
}
};
priority_queue<pair<int,struct node *>, vector<pair<int,struct node *> >, compare > pq(m1.begin(),m1.end());

Missing nullptr for undeclared array element

I am trying to make a basic HashMap. I am checking to see if an element exists at an index before inserting it there. When I insert my first element, it says that an element already exists at that position. I have gone through the debugger, and all of my values are as expected, except for map[hash]. I am anticipating a nullptr, but it is not coming. map[hash] has the following value:
- map[hash] 0xcdcdcdcd {key=??? value={...} next_element=??? } HashElement *
Can someone please explain to me what I am misunderstanding here? The unexpected result is on line 21 of HashMap.cpp. Here is the relevant code:
HashMap.h
#pragma once
#include <string>
#include "HashElement.h"
class HashMap
{
private:
HashElement **map;
int size;
public:
HashMap(int);
~HashMap();
int GetHash(int);
void Put(int, std::string);
};
HashMap.cpp
#include "HashMap.h"
#include <string>
HashMap::HashMap(int _size)
{
size = _size;
map = new HashElement*[size];
}
HashMap::~HashMap()
{
}
int HashMap::GetHash(int _key){
return _key % size;
}
void HashMap::Put(int _key, std::string _value){
int hash = GetHash(_key);
if (!map[hash]){ //Anticipated to be nullptr on first Put, but it skips to else
map[hash] = new HashElement(_key, _value);
}
else{
HashElement *lastElement = map[hash];
while (lastElement->next_element){
lastElement = lastElement->next_element;
}
lastElement->next_element = new HashElement(_key, _value);
}
}
HashElement.h
#pragma once
#include <string>
class HashElement
{
private:
int key;
std::string value;
public:
HashElement(int, std::string);
~HashElement();
HashElement *next_element;
int get_key();
std::string get_value();
};
HashElement.cpp
#include "HashElement.h"
HashElement::HashElement(int _key, std::string _value)
{
key = _key;
value = _value;
}
HashElement::~HashElement()
{
}
int HashElement::get_key(){
return key;
}
std::string HashElement::get_value(){
return value;
}
map[hash] is not a nullptr because you haven't initialized it to such.
map = new HashElement*[size];
Each element in the map array will have a random value after that line.
To fix this and initialize all elements to be nullptr:
map = new HashElement*[size]();
^^
map = new HashElement*[size];
Here, you are instantiating an array of size pointers, on the heap. As I understand your question, you are assuming that all of the instantiated pointers, in this new array, will be nullptr.
That is not the case. For "plain old data", or POD, its contents are not initialized by default. You'll have to explicitly initialize them:
for (size_t i=0; i<size; ++i)
map[i]=0;
... in the constructor

C++ map insert with custom key fails

I have a custom class as a key in a map. When I try to insert an item into the map, the program terminates. There has to be a problem with the creation of the key.
class MyKey {
char* data;
bool operator<(const MyKey& s) const {
for(int i = 0; i < (int)(sizeof(data)/sizeof(char)); i++) {
if(data[i] > s.data[i])
return false;
}
return true;
}
}
map<MyKey, char>* map = new map<MyKey, char>;
MyKey* key = new MyKey(...);
map->insert(make_pair(*key, '0'));
The program terminates at the insert.
You can't determine the size of an array from the pointer alone like you're attempting to-do in the for-loop of your operator< function ... You will have to, at some point, pass in the size of the array that is being pointed to by data so that you don't overflow the bounds of the array data is pointing to. Since data is a pointer, sizeof(data) simply returns the size of a pointer on your platform, not the size of the array being pointed to by data.
For C++, rather than using an allocated array, you should possibily use a STL container that you can directly query for the size of the container object ... this could include std::string if it's string-data, or std::vector<unsigned char> if it's just a bunch of binary bytes.
The following works and prints A.
#include <iostream>
#include <map>
using namespace std;
class Key
{
public:
Key(int x):data(x) {}
bool operator<(const Key &k) const { return(data < k.data); }
private:
int data;
};
int main()
{
Key myKey(10);
map<Key, char> m;
m.insert(make_pair(myKey, 'A'));
map<Key, char>::iterator it = m.find(myKey);
if (it != m.end())
{
cout << (*it).second << endl;
}
}
From your example code, the operator < would not be called because you only insert one element in the map. And you said you don't implement a copy constructor. So following code would be a problem:
class MyKey {
public:
MyKey()
{
data = new char[10];
}
~MyKey()
{
delete data;
}
private:
char* data;
};