Iterating through multiple sequential lists in c++ - c++

I'm trying to simply iterate through a list, made up of two list objects I have. I want to do this without having to create a third list variable object that is the concatenation of the two, and without two separate loops going each through a list respectively.
I'm pretty sure I've done this before, but I can't find how to do it anymore.
This is the code that I am trying but it doesn't work properly, as it takes what I've written as a list of lists. That is not my intention. I'm looking for it to iterate through elements of list1, then elements of list2. I'm convinced there is a way to format the {list1, list2} within the statement so that this is the case.
for (auto e : {list1, list2}) { // How can I formulate <<<list1, list2>>>
// so that it takes the concatenation of list elements?
std::cout << e << newLine;
}
Looking to have an output like: list1[0], list1[1], list2[0], list2[1].
A simple way to test effectiveness is whether auto registers as the "list type" or the "element type". I'm looking for the element type.

Something along these lines perhaps:
for (auto& l : {list1, list2}) {
for (auto& e : l) {
std::cout << e;
}
}

Related

Creating a List Specification in Alloy Language

I'm working on defining a List in Alloy but I'm stuck.
This is what I have so far (it acts like a LinkedList):
module List
// The List signature
lone sig List { rootElement: lone Element }
// A list element signature
sig Element { nextElement: lone Element }
// Prevents an Element from referencing itself
fact preventElementLooping {
no ele: Element | ele = ele.nextElement
}
// Zero Element outliers
fact allElementsBelongToOneList {
all ele: Element | one list: List | ele in list.rootElement.*nextElement
}
// Prevents Elements from referencing a Element before it in the List
fact preventCycle {
no ele: Element | ele in ele.^nextElement
}
This all looks good to me and I feel like this is correct.
I'm trying to define 3 predicates for this list definition:
Create: Should create an empty list
Put: Should add an item to the end of the list
Find: Should return all indices in the list that match a given element
pred create(list, list":List) {
list".rootElement = none
}
pred put(list, list":List, ele: Element) {
list".rootElement = ele
}
pred find [list:List, ele: Element] {
ele = list.rootElement or ele in list.rootElement.^nextElement
}
This is what I need help with I feel like I'm missing something in those 3 preds.
My questions:
Am I over complicating things by trying to use a linked list? How would you just do a normal list?
Put is correct for the first put but fails when you need to put again as it just replaces the root element
Find is the big struggle. I need to store the indices somewhere to return them right? Also I thought alloy only had bare bones understanding of Numbers for indexes (I believe only allowing -7 to 8). Should index be its own signature?
Thanks in advance
There are several ways to define a notion of list in Alloy, yours is a possibility, depending no what you expect to do then.
I don't see why you want to make List a lone sig?
Another remark is that your list doesn't contain any data, only "elements" (I would call them cells), perhaps because it's of no use in your spec? Anyhow, you could make your module generic and store data in cells, e.g.:
module List[Data]
sig List { rootElement: lone Element }
sig Element { data: one Data, nextElement: lone Element }
Your facts can also be improved:
By having only one fact rejecting all forms of cycles.
By only asking for elements to belong to some list rather than exactly one.
Finally, regarding operations, I suggest you take a look at how the standard library models lists and operations:
util/seqrel specifies lists as relations
util/sequence specifies lists as signatures holding elements
util/sequniv is like util/seqrel but relies on builtin integer indices and is implemented in an ad hoc concrete syntax based on the seq keyword.

Best way to group string members of object in a vector

I am trying to store a vector of objects and sort them by a string member possessed by each object. It doesn't need to be sorted alphabetically, it only needs to group every object with an identical string together in the vector.
IE reading through the vector and outputting the strings from beginning to end should return something like:
string_bulletSprite
string_bulletSprite
string_bulletSprite
string_playerSprite
string_enemySprite
string_enemySprite
But should NEVER return something like:
string_bulletSprite
string_playerSprite
string_bulletSprite
[etc.]
Currently I am using std:sort and a custom comparison function:
std::vector<GameObject*> worldVector;
[...]
std::sort(worldVector.begin(), worldVector.end(), compString);
And the comparison function used in the std::sort looks like this:
bool compString(GameObject* a, GameObject* b)
{
return a->getSpriteNameAndPath() < b->getSpriteNameAndPath();
}
getSpriteNameAndPath() is a simple accessor which returns a normal string.
This seems to work fine. I've stress tested this a fair bit and it seems to always group things together the way I wanted.
My question is, is this the ideal or most logical/efficient way of accomplishing the stated goal? I get the impression Sort isn't quite meant to be used this way and I'm wondering if there's a better way to do this if all I want to do is group but don't care about doing so in alphabetic order.
Or is this fine?
If you have lots of equivalent elements in your range, then std::sort is less efficient than manually sorting the elements.
You can do this by shifting the minimum elements to the beginning of the range, and then repeating this process on the remaining non-minimum elements
// given some range v
auto b = std::begin(v); // keeps track of remaining elements
while (b != std::end(v)) // while there's elements to be arranged
{
auto min = *std::min_element(b, std::end(v)); // find the minimum
// move elements matching that to the front
// and simultaneously update the remaining range
b = std::partition(b, std::end(v),
[=](auto const & i) {
return i == min;
});
}
Of course, a custom comparator can be passed to min_element, and the lambda in partition can be modified if equivalence is defined some other way.
Note that if you have very few equivalent elements, this method is much less efficient than using std::sort.
Here's a demo with a range of ints.
I hope I understood your question correctly, if so, I will give you a little example of std::map which is great for grouping things by keys, which will most probably be a std::string.
Please take a look:
class Sprite
{
public:
Sprite(/* args */)
{
}
~Sprite()
{
}
};
int main(int argc, char ** argv){
std::map <std::string, std::map<std::string, Sprite>> sprites;
std::map <std::string, Sprite> spaceships;
spaceships.insert(std::make_pair("executor", Sprite()));
spaceships.insert(std::make_pair("millennium Falcon", Sprite()));
spaceships.insert(std::make_pair("death star", Sprite()));
sprites.insert(std::make_pair("spaceships",spaceships));
std::cout << sprites["spaceships"]["executor"].~member_variable_or_function~() << std::endl;
return 0;
}
Seems like Functor or Lambda is the way to go for this particular program, but I realized some time after posting that I could just create an ID for the images and sort those instead of strings. Thanks for the help though, everyone!

Where will a new element be inserted in a std::set?

I have a loop like this (where mySet is a std::set):
for(auto iter=mySet.begin(); iter!=mySet.end(); ++iter){
if (someCondition){mySet.insert(newElement);}
if (someotherCondition){mySet.insert(anothernewElement);}
}
I am experiencing some strange behavior, and I am asking myself if this could be due to the inserted element being inserted "before" the current iterator position in the loop. Namely, I have an Iteration where both conditions are true, but still the distance
distance(iter, mySet.end())
is only 1, not 2 as I would expect. Is my guess about set behavior right? And more importantly, can I still do what I want to do?
what I'm trying to do is to build "chains" on a hexagonal board beween fields of the same color. I have a set containing all fields of my color, and the conditions check the color of neighboring fields, and if they are of the same color, copy this field to mySet, so the chain.
I am trying to use std::set for this because it allows no fields to be in the chain more than once. Reading the comments so far I fear I need to swich to std::vector, where append() will surely add the element at the end, but then I will run into new problems due to having to think of a way to forbid doubling of elements. I therefore am hoping for advice how to solve this the best way.
Depending on the new element's value, it may be inserted before or after current iterator value. Below is an example of inserting before and after an iterator.
#include <iostream>
#include <set>
int main()
{
std::set<int> s;
s.insert(3);
auto it = s.begin();
std::cout << std::distance(it, s.end()) << std::endl; // prints 1
s.insert(2); // 2 will be inserted before it
std::cout << std::distance(it, s.end()) << std::endl; // prints 1
s.insert(5); // 5 will be inserted after it
std::cout << std::distance(it, s.end()) << std::endl; // prints 2
}
Regarding your question in the comments: In my particular case, modifying it while iterating is basically exactly what I want, but of course I need to add averything after the current position; no you can not manually arrange the order of the elements. A new value's order is determined by comparing the new one and existing elements. Below is the quote from cppreference.
std::set is an associative container that contains a sorted set of unique objects of type Key. Sorting is done using the key comparison function Compare. Search, removal, and insertion operations have logarithmic complexity. Sets are usually implemented as red-black trees.
Thus, the implementation of the set will decide where exactly it will be placed.
If you really need to add values after current position, you need to use a different container. For example, simply a vector would be suitable:
it = myvector.insert ( it+1 , 200 ); // +1 to add after it
If you have a small number of items, doing a brute-force check to see if they're inside a vector can actually be faster than checking if they're in a set. This is because vectors tend to have better cache locality than lists.
We can write a function to do this pretty easily:
template<class T>
void insert_unique(std::vector<T>& vect, T const& elem) {
if(std::find(vect.begin(), vect.end(), elem) != vect.end()) {
vect.push_back(elem);
}
}

External Doubly Linked-list Iterator c++

I made a doubly linked list. In my main, I need to use an external List Iterator that has a constructor that takes a list. This is what I have so far:
struct ListIterator : List {
Node* cur = head;
ListIterator(List* list) {
this -> list = list;
}
bool hasNext() {
return (cur -> next) != nullptr;
}
int next() {
return list.at(cur -> next);
}
};
This is my main:
List list1;
list1.append('I');
list1.append('D');
list1.append('F');
list1.append('G');
ListIterator it(list1);
while (it.hasNext()) {
cout << it.next();
}
As you can see, I'm trying to use hasNext() and next() to display all the nodes in a list. I'm confused on how to create a constructor that takes a list and use the function in ListIterator struct. Any tips and hints would be very much appreciated.
You seem to be heavily influenced by Java (or perhaps even C#). It's not a bad thing, you just need to learn the ins and outs of C++.
For your first problem: in C++, there is a clear distinction between values, references and pointers. When you declare an instance of your List class as follows:
List list1;
that is actually a value. The instance exists on the stack and will be properly disposed off (the destructor will be called) once the scope is ended.
If you now were to initialize a second list as follows:
List list2 = list1;
that is also a value, and it will copy the entire list (the copy constructor or assignment operator will be called). Now list1 and list2 are two distinct list instances and modifying one will not affect the other.
Anyhow, to get a pointer to a list, you need the following syntax:
List *listPtr1 = &list1;
As it is a pointer, an indirection, copying it will not copy the underlying structure:
List *listPtr2 = listPtr1; // Will also point to list1
While using the proper syntax will solve your immediate problem, it doesn't properly address the odd iterator implementation.
In C++, iterators either point to a single element in a container or they point past-the-end. An iterator typically does not know if the end of the container is reached by itself; instead, it needs to be compared to this past-the-end iterator.
Containers typically define a begin method that returns an iterator to the first element, and an end method that returns an iterator to past-the-end.
Iterating over a container typically happens using the following prototype:
for (auto it = container.begin(); it != container.end(); ++it)
{
// To access the element, you need to dereference the iterator:
std::cout << "The current value is :" << *it << std::endl;
}
In this regard, iterators behave much like pointers to the elements. There's no need for the clunky next and hasNext methods. You simply get an iterator to the start of your container, make sure to stop iterating once it points to past-the-end, and increment it when you want to go to the next element.
A container that properly defines the begin and end methods can also be used in a range-based for loop:
for (auto &element : container)
{
std::cout << "The current value is :" << element << std::endl;
}
I understand it is fun and very educational to implement your own containers. I reinvented my fair share of wheels just to understand how things work exactly, so nothing wrong with that. But I would advice you to perhaps play around with standard C++ containers first, get the hang of the major differences between C++ and languages like Java and C# and then have another go at the exercise.

What can bring a std::map to not find one of its keys?

I have a std::map associating const char* keys with int values:
std::map<const char*, int> myMap;
I initialize it with three keys, then check if it can find it:
myMap["zero"] = 0;
myMap["first"] = 1;
myMap["second"] = 2;
if (myMap.at("zero") != 0)
{
std::cerr << "We have a problem here..." << std::endl;
}
And nothing is printed. From here, everything looks ok.
But later in my code, without any alteration of this map, I try to find again a key:
int value = myMap.at("zero");
But the at function throws an std::out_of_range exception, which means it cannot find the element. myMap.find("zero") thinks the same, because it returns an iterator on the end of the map.
But the creepiest part is that the key is really in the map, if just before the call to the at function, I print the content of the map like this:
for (auto it = myMap.begin(); it != myMap.end(); it++)
{
std::cout << (*it).first << std::endl;
}
The output is as expected:
zero
first
second
How is it even possible? I don't use any beta-test library or anything supposed to be unstable.
You have a map of pointers to characters, not strings. The map lookup is based on the pointer value (address) and not the value of what's pointed at. In the first case, where "zero" is found in the map, you compiler has performed some string merging and is using one array of characters for both identical strings. This is not required by the language but is a common optimization. In the second case, when the string is not found, this merging has not been done (possibly your code here is in a different source module), so the address being used in the map is different from what was inserted and is then not found.
To fix this either store std::string objects in the map, or specify a comparison in your map declaration to order based on the strings and not the addresses.
key to map is char * . So map comparison function will try to compare raw pointer values and not the c style char string equivalence check. So declare the map having std::string as the key.
if you do not want to deal with the std::string and still want the same functionality with improved time complexity, sophisticated data structure is trie. Look at some implementations like Judy Array.