Create unique set of maps in Dart - dart

I need to create a unique set of maps but it seems that adding maps to a set doesn't filter and adds duplicates.
Set mySet = Set();
List myList = [
{"name": "Jane"},
{"name": "Jane"},
{"name": "Mary"}
]
for(var item in myList){
mySet.add(item);
}
Doing this causes the set to contain all three maps. Is there any way to only have one Jane?

Other than doing what #Patrick suggested, you also have to major ways:
If your map is constant just declare it as a const so they will reference always the same object, hence the Set will work as you expect to:
List myList = const [
{"name": "Jane"},
{"name": "Jane"},
{"name": "Mary"}
]
Check if a map with the same name already exists before adding the new one:
for(var item in list){
// If a map with the same name exists don't add the item.
if (set.any((e) => e['name'] == item['name'])) {
continue;
}
set.add(item);
}
Just a quick note, you can initialize a Set using its literal constructor (there is a linter rule about this):
var set = <Map<String, String>>{}

This is because the Maps are different: {"name": "Jane"} != {"name": "Jane"}.
You have to create your own class and override == (and hashCode).
See "Implementing map keys":
https://dart.dev/guides/libraries/library-tour

Related

Cannot modify some values in a deep-copied nested Map

I'm new to Dart.
I have a constant Map that defines some kind of data schema, that way:
const Map<String, dynamic> FILE_STRUCT = {
"dt": {
"a": [],
"b": [],
"c": [],
},
"os": null,
"pm": null,
"p": "1",
};
Then, later, I want to use that structure to create a Map and add elements to it. So I deep-copy this Map to a new Map var, so I can add elements in it, that way:
Map data = {...FILE_STRUCT};
When I do data["os"] = "newValue"; I don't have any issue. But when I do:
List<List> aValues = [[1,2,3], [4,5,6]];
data["dt"]["a"] = aValues;
But when I do that, I get this error:
UnsupportedError (Unsupported operation: Cannot modify unmodifiable map)
I thought the var data was modifiable. So what is happening here, and what would be the proper way to modify the nested Map?

Searchkick: how to save records in ElasticSearch in different indices based on record timestamp?

I have a Rails Model with Searchkick.
I want my model instances to be saved in ElasticSearch in different indices based on the month creation of the instance.
Lets say I have the following instances in my Model:
A created the 03/25/2021
B created the 03/28/2021
C created the 04/01/2021
Instead of having one ES index (which is the default behavior for Searchkick), how can I store when my instances are created:
A & B in ES index labeled: model_2021_03
C in ES index labeled: model_2021_04
From what I understand, there are two main steps:
Create Multiple Index(indices)
Store the document in one of those index.
Idea here is making the index as "Write_Index" in which you want to put the document and mark others as "Read_Index".
So you can start with:
1. Creating an Index Template.
PUT /_index_template/model_template
{
"index_patterns": [
"model*"
],
"priority": 1,
"template": {
"aliases": {
"model":{}
},
"mappings": {
"dynamic":"strict",
"_source":
{"enabled": false},
"properties": {
//your filed mappings here
}
},
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 3
}
}
}
}
2.Create an index for a particular month,which will follow the model template(in step 1) with an naming strategy in your code
PUT model_YYYY_MM
Ex: lets say, you create two index model_2021_03, model_2021_04, now you want to store the documents in one of them,
Idea here is to mark the index, that you want to store the document in
as "Write_Index" and all other as "Read_Index", so when you store the
document using alias name("model") here, it will get stored in write
index by default.
3. Making the index as write index and others as read
POST /_aliases
{
"actions": [
{"add":
{"index": "model_2021_04",
"alias": "model",
"is_write_index": true}
},
{"add":
{"index": "model_2021_03",
"alias": "model",
"is_write_index": false}
}
]
}
4.Finally putting documents in index using alias name
PUT /model/_doc/1
{
//your data here
}

After adding arrays together, is there a way to know which elements came from which parent array?

Here's the JSON i'm working with:
{
"featured": [
{
"name": "Featured Show number 1",
"id": "123",
"slug": "featured-show-number-one",
"description": "This is an item description for show number 1"
},
{
"name": "Featured Show number 2",
"id": "456",
"slug": "featured-show-nubmer-tow",
"description": "This is an item description for show number 2"
}
],
"nonfeatured": [
{
"name": "Show number 3",
"id": "789",
"slug": "show-number-three",
"description": "This is an item description for show number 3"
},
{
"name": "Show number 4",
"id": "135",
"slug": "show-number-four",
"description": "This is an item description for show number 4"
}
]
}
What I am trying to figure out is after I parse this JSON using two data models, one for "Featured" and one for "Nonfeatured", looping through each show and adding it to an array, I need to add the arrays of shows together to create one array containing all the shows. However, I need to keep track of which shows are featured and which ones are non featured from the single array. Is there a way to do this?
The short answer to your specific question here is 'no'. The result of adding array A and array B (where both contain the same types) is A + B; there is no metadata providing any kind of source information.
But that is not to say that you couldn't accomplish the same thing by changing the model slightly. One option would be to add an extra boolean flag to the model called isFeatured or similar. Or you could 'future-proof' any work by using an enumeration of source lists containing featured, non-featured plus anything else you may require later.
To take the first example, an option would be to add the boolean field and then call code similar to below prior to 'summing' the arrays.
arrayA.forEach { $0.isFeatured = true }
arrayB.forEach { $0.isFeatured = false }
let arrayC = arrayA + arrayB
Then each element in the summed array will tell you its source list.

Swift Filter same location coordinates contained inside an array of objects

I am receiving from Server, a list of Stores information in an array of objects. Below is a sample -
"stores": [
{
"name": “Store 1”,
"number": "5381",
"country": "BELGIE",
"latLng": [
50.730614,
4.231847
]
},
{
"name": "Store 2”,
"number": "5220",
"country": "BELGIE",
"latLng": [
50.730614,
4.231847
]
},
{
"name": "Store 3”,
"number": "3982”,
"country": "BELGIE",
"latLng": [
50.7315706,
4.2303477
]
},
{
"name": "Store 4”,
"number": "4179",
"country": "BELGIE",
"latLng": [
50.7262577,
4.245589
]
}]
What am I trying?:
I need to filter out the stores in the array that has same latLng values.
Why?
I need to identify these 'same latLng' values and add an offset of some value like 0.001 to the latitude value so that when I show these stores on a map, the stores on same location appear side by side.
I found this (answer by Rob B) as reference for this approach.
What I need?
1. How can I filter with values inside of an object in the array?
I tried something like this inside a for loop -
print("\(allStoresInfo.filter({ $0.latLng![0] == $0.latLng![0] }).count)")
This value always returns 4. I know I am missing some basic sense here but need know what it is :-(
After I filter and add the offset for same values, how do I update my array with these updated values?
The following method modifies in place the latitude of each store that matches the latitude of another store:
allStoresInfo.map{ currentStore in allStoresInfo.filter{$0.latLng![0] == currentStore.latLng![0]}.enumerated().forEach{ index, matchingStore in
matchingStore.latLng![0] += Double(index)*0.001
}
}
Just a small piece of advice: don't store lat-long values in an array. Either create a struct/class for them or use a tuple to store them.

How to get other documents' data by document id in map function

I have a problem "joining" some documents in a view. Here's my schema: Documents with type "category" can hold an embedded array of ids to documents with type "page". Both have a field "name".
My Documents:
{
"_id": "887c28dcf6dd8429d404d276b900b203",
"_rev": "3-c4d1e0c8378bb0081b5fe3522ee649a0",
"TYPE": "category",
"NAME": "Home",
"PAGES": [
{"PAGE_ID": "887c28dcf6dd8429d404d276b900ad8f"},
{"PAGE_ID": "887c28dcf6dd8429d404d276b900b203"},
{"PAGE_ID": "887c28dcf6dd8429d404d276b900bae0"}
]
}
{
"_id": "887c28dcf6dd8429d404d276b9008c01",
"_rev": "1-afd54c654ae5afa56a3fbd7b1ba119d2",
"TYPE": "page",
"NAME": "Foo"
}
Now I want to join these in a view with this map function:
function(doc) {
if (doc.TYPE == "category") {
for (id in doc.PAGES) {
emit(doc.NAME, doc.PAGES[id].PAGE_ID);
}
}
}
But instead of the PAGE_ID I want the NAME of the referencing document.
This is basically the example from the CouchDB wiki, but they don't show the map function. So any ideas?
You need to include a _id field somewhere in your output value. After that, you use include_docs=true and the view will include the linked document instead of the source document. For example:
function(doc) {
if (doc.TYPE == "category") {
for (var x = 0; x < doc.PAGES.length; x++) {
emit(doc.NAME, { _id: doc.PAGES[x].PAGE_ID });
}
}
}
When you query this view, you add include_docs=true to your URL. And your view output will add a new field to each row called doc. Ordinarily, that field will contain the full source document. In this case, it will include the linked document you are referring to.
EDIT Btw, you're using the for...in loop incorrectly. A for...in is used to loop over the properties of an object. You need to use a simple for loop to iterate an array like this.

Resources