In flutter/dart, how can I add elements to a list whilst ensuring that every new entry is unique (i.e. no duplicates).
So we know how to add elements to a list:
List myList = [];
then
myList.add(...);
but I'd like to know how to make sure that whatever has been added has not been added before.
Many thanks,
You should consider using a set. A set is an unordered collection of unique items.
var mySet = <String>{};
mySet.add('something');
Optionally, you may use the Dart´s Extensions function
extension ListExtension<E> on List<E> {
void addAllUnique(Iterable<E> iterable) {
for (var element in iterable) {
if (!contains(element)) {
add(element);
}
}
}
}
Use a Map for the initial adding, Maps will not let duplicates then convert from Map to list.
Maps are Name Value pairs so if these are strings just set the name and value the same, if it is an object set the "uniqueID" as the name and the object as the value...
Then you can take the Name set or usually Value set and turn that into a list for iteration and looping.
https://www.tutorialspoint.com/dart_programming/dart_programming_map.htm
Related
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.
I am interested in performing the following operations on a set of data.
First, we are given a set of keys, as an example:
vector<int> keys{1,2,3,4,5,6};
Each of these keys is understood to be pointing to a unique entry (which is not important to specify, rather what is important is the relation whether each key is pointing to a separate entry, or some keys are pointing to the same entry). Initially, we do not know whether any key is pointing to the same entry or not, so we start out with a data structure that treats all entries as separate for each key:
surjectiveData<int> data;
data.populateUnique(keys.begin(),keys.end());
Graphically, we can illustrate the current state of data as
where we use labels a,b,c,d,e,f to keep track of the unique entries in data. Now, consider adding additional information on which keys are pointing to the same entry. For example:
vector<pair<int,int>> identifications{make_pair(1,2),make_pair(3,4),make_pair(2,4),make_pair(5,6)};
data.couple(identifications.begin(),indentifications.end());
The couple method of surjectiveData goes through the pairs provided and makes them point to the same unique entry. Graphcally, the four identifications would in turn change data as follows:
and now there are only two unique entries in data, which here we denote abcd and ef. Note that once two or more keys point to the same entry, it does not matter which of these keys is identified with which of separate keys, all of them point to the same entry after identification.
Now that we are done with specifying key identifications, we could think of using data as follows. For example, we could ask what is the effective number of unique remaining entries
cout<<data.size()<<endl; // 2
Or, we could iterate through the entries and check how many keys point to each of them
for(auto it=data.begin();it!=data.end();it++){
cout<<it->size()<<" ";// 4 2
}
Ideally, internally the structure should take constant time for each identification, if possible.
I tried to search for such a data structure in the standard library, but could not find any. Did I miss it? Perhaps there is a smart way to implement it based on more basic objects? If so, what would be a minimal example for integers?
The operations you describe can be supported with a disjoint set data structure: https://en.wikipedia.org/wiki/Disjoint-set_data_structure
This is a linked data structure that supports 3 operations:
makeSet() creates a new singleton set and returns its element
union(a,b) given two elements, merges the sets that contain them. One element of each set will be the "representative" of that set
find(a) returns the representative of the set that contains a.
All operations take pretty much constant amortized time.
I usually implement this data structure in a single vector, where each array index denotes is a set element. If its value is >0, then it's a set representative and the value is the size of the set. If its value is < 0 then its value is ~p, where p is its "parent" element in the same set. Sometimes I use the 0 value for "uninitialized".
It's not hard to keep track of the number of sets.
in C++, my usual implementation would look like this:
class DijointSets {
unsigned num_sets;
std::vector<int> sets;
public:
// Create a new singleton set and return its element
unsigned make_set() {
unsigned ret = (unsigned)sets.size();
sets.push_back(1);
++num_sets;
return ret;
}
// Find the representative element of an element's set
unsigned find(unsigned x) {
int p = sets[x];
if (p>=0) {
return x;
}
p = find(~p);
sets[x] = ~p; //might be the same
return p;
}
// Merge the sets that contain two elements
// returns true if a merge was done
boolean union(unsigned a, unsigned b) {
a = find(a);
b = find(b);
if (a==b) {
return false;
}
if (sets[a] > sets[b]) {
sets[a] += sets[b]; //add sizes
sets[b] = ~(int)a;
} else {
sets[b] += sets[a]; //add sizes
sets[a] = ~(int)b;
}
--num_sets;
return true;
}
// get the size of an element's set
unsigned set_size(x) {
return sets[find(x)];
}
// get the number of sets
unsigned set_count() {
return num_sets;
}
}
I am doing a practice in C++ based on data structures.
My class contains an attribute like this map<int, list <Route *>>. My question is, what happens when I add a key to the map. Must I initialize the list or not? My wish is to have an empty file in the description of that key.
Something like this is what I thought:
map<int, list<Route* > >::iterator it= _mapRoutesAirline.find(IDAirline);
if(it == _mapRoutesAirline.end())
_mapRoutesAirline[IDAirline] = list<Route*>();
Yes, you can simply assign to the map element (syntax assuming C++11 or above):
_mapRoutesAirline[IDAirline] = {};
Note that in many use cases you don't have to assign an empty list, because any attempt to access a key that isn't present in the map yet will automatically create a default constructed list for that key, which is an empty list. This means that, for example, _mapRoutesAirline[42] would return an empty list if you hadn't assigned anything to the _mapRoutesAirline[42] yet.
Yes you can add an empty list to the map as value e.g.:
if(it == _mapRoutesAirline.end())
_mapRoutesAirline.insert(std::make_pair(IDAirline, list<Route*>{}));
You can create an empty list when you define a new key, no need to define the data type of the list.
_mapRoutesAirline[IDAirline] = {};
Also, you don't need to define an iterator just to find and insert element
It can be done in this way
if(_mapRoutesAirline.find(IDAirline) == _mapRoutesAirline.end()){
_mapRoutesAirline[IDAirline] = {};
}
I have a Java program that I want to convert it to C++. So, there is a Linkedhashmap data structure used in the Java code and I want to convert it to C++. Is there an equivalent datatype for LinkedHashmap in C++?
I tried to use std::unordered_map, however, it does not maintain the order of the insertion.
C++ does not offer a collection template with the behavior that would mimic Java's LinkedHashMap<K,V>, so you would need to maintain the order separately from the mapping.
This can be achieved by keeping the data in a std::list<std::pair<K,V>>, and keeping a separate std::unordered_map<k,std::list::iterator<std::pair<K,V>>> map for quick look-up of the item by key:
On adding an item, add the corresponding key/value pair to the end of the list, and map the key to the iterator std::prev(list.end()).
On removing an item by key, look up its iterator, remove it from the list, and then remove the mapping.
On replacing an item, look up list iterator from the unordered map first, and then replace its content with a new key-value pair.
On iterating the values, simply iterate std::list<std::pair<K,V>>.
The insertion order contract on key iteration can be achieved with a balanced tree for log(n) performance. This is better than maintaining keys in a list as item removal requires n lookup time. My mantra is never put something you look up in a list. If it doesn't have to be sorted, use a hash. If it should be sorted, use a balanced tree. If all you're going to do is iterate, then a list is fine.
In c++ this would be std::map where the key is the item reference and the value is the insertion order, the keys are sorted using red-black trees. See: Is there a sorted container in STL
This is how I do it:
map<TKey, set<MyClass<K1,K2>, greater<MyClass<K1, K2>>>> _objects; // set ordered by timestamp. Does not guarantee uniqueness based on K1 and K2.
map<TKey, map<K2, typename set<MyClass<K1, K2>, greater<MyClass<K1, K2>>>::iterator>> _objectsMap; // Used to locate object in _objects
To add object id:
if (_objectsMap[userId].find(id) == _objectsMap[userId].end())
_objectsMap[userId][id] = _objects[userId].emplace(userId, id).first;
To erase an object id:
if (_objectsMap[userId].find(id) != _objectsMap[userId].end()) {
_objects[userId].erase(_objectsMap[userId][id]);
_objectsMap[userId].erase(id);
}
To retrieve, say the most recent size objects from the list starting from a specific object id:
vector<K2> result;
if (_objectsMap[userId].find(id) != _objectsMap[userId].end() && _objectsMap[userId][id] != _objects[userId].begin()) {
set<MyClass<K2, K2>, greater<MyClass<K1, K2>>>::iterator start = _objects[userId].begin(), end = _objectsMap[userId][id];
size_t counts = distance(_objects[userId].begin(), _objectsMap[userId][id]);
if (counts > size)
advance(start, counts - size);
transform(start,
end,
back_inserter(result),
[](const MyClass<K1, K2>& obj) { return obj.ID(); });
}
return result;
So i'm fairly new to c++ and i'm a little confused on how to implement the find() function on my set which is storing a pair item. Ive read on how to insert and remove items by their pair but came up dry on anyone explaining how to use find (Or some other method, if there is one) to find a value by the first item of the pair.
set<pair<string, CustomObject>> *items = new set<pair<string, CustomObject>>();
Then lets say I insert a few pairs into the set then I want to find one of those pair by searching for the "key" being stored as the first item in the pair. I think it would involve calling the .first on the pair but im just having trouble with that. This is the basic function im trying to implement
bool inSet(string key){
return this->items->find(pair<string, CustomObject>(key, null).first)
}
I was able to implement everything just fine in a map object but then I had to switch to a set because I wanted to be able to sort the items in the data structure and I was told that you cant efficiently do this in a map, hence the set.
std::set stores and searches for values based on the entire value. So when you do a find for pair(key, null), and the set contains pair(key, somevalue), it won't find it, as they are not the same.
If you want to search by just the key, you need a std::map. As you say, that doesn't do any searching or sorting by the value, so you can only have one entry with a given key.
If you want to search/sort by both just the key and the key,value pair (different searches at different points in the lifetime of the same data structure), then you'll need a more complex arrangement.
a map of sets can do what you want:
std::map<string, std::set<CustomObject>> items;
Now when you just want to look up things by key, you just lookup in the map, getting back a set of all the values with that key. If you want to search further for a specific value, you look it up in that set.
To find key in std::set by key stored in pair you need to redefine order comparision procedure for your set (if you need multiple objects use multiset):
typedef pair<string, CustomObject> SetValue
struct CustomObjectCompare {
bool operator() (const SetValue& lhs, const SetValue& rhs) const{
return rhs.first < rhs.first;
}
};
// use multiset insead of set if you need multiple objects per one key
typedef set<pair<string, CustomObject>, CustomObjectCompare> Set;
Set mySet;
bool inSet(string key){
static CustomObject emptyObject;
return mySet.end() != mySet.find(SetValue(key, emptyObject))
}
This example define comparision object CustomObjectCompare and special set class Set with that comparision object. As search as sorting will be only by string. The function isSet search by string and emptyObject is ignored and may be any of existed object. In example it is an function internal once initialized static object.