Dart - For loop is changing elements of my list even when it is cloned - flutter

When I access to the elements of my list in a for loop, I would like to be able to modify them without impacting the original list.
Here's a simple example :
List pairs = [
[1,8],
[1,6],
];
print(pairs);
List copy = List.from(pairs);
for (List pair in copy) {
if(pair.contains(1)) {
pair.remove(1);
}
}
print(pairs);
The output of this is :
[[1, 8], [1, 6]]
[[8], [6]]
I expected the output to be :
[[1, 8], [1, 6]]
[[1, 8], [1, 6]]
I tried to replace List copy = List.from(pairs); with :
List copy = [...pairs]; // This
List copy = []..addAll(pairs); // Or this
Nothing is working.
The only solution I found was to do this :
List temp = List.from(pair);
if(temp.contains(1)) {
temp.remove(1);
}
But it seems to be a bit overkill. Does anyone has another idea ?

As jamesdlin says, using List.from or the spread operator just creates a shallow copy of the list. Dart does not have a built-in deep copy function that I could find, but if you'll only be working with nested lists like this we can define our own pretty easily:
List<T> deepCopy<T>(List<T> list) =>
list.map((e) => e is List ? deepCopy(e) : e).cast<T>().toList();
Here's a dartpad showing the result.

Related

How to add a new value to Map in Dart?

this is my first post to StackOverflow.
I have been struggling with the Map data.
It’s been taking too much time to find a way more than I thought...
Ex)
Map<String, int> someMap = {
"a": 1,
"b": 2,
"c": 3,
};
How can I add a new value to the same key Map?
like this.
a:1, b:2, c:3,4,5,6etc....
I'd be grateful if you could tell me the correct way.
Thank you.
If you want multiple values for the same key, you'll need to change the value type: Right now it's int, but that can only be a single int, and by definition, a key only occurs once in a map.
If you change the type of the value to List<int>, you can add multiple values for the same key:
Map<String, List<int>> someMap = {
"a": [1],
"b": [2,3],
"c": [4],
};
Now, to add more values, you could simply access the list and add values to it:
someMap["c"].add(5); // c: [4, 5]
someMap["c"].addAll([6,7,8]); // c: [4, 5, 6, 7, 8]

How to store a simple matrix in Cloud Firestore using Dart/Flutter?

Let's say I have the following integer matrix in Dart:
final List<List<int>> myMatrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];
Then I try to store it in Cloud Firestore like this:
await Firestore.instance.collection("anyCollection").add({
"matrix" : myMatrix,
});
But as soon as I run the code above, the simulator crashes and I get the following error:
*** First throw call stack:
(
0 CoreFoundation 0x00007fff23c4f02e __exceptionPreprocess + 350
1 libobjc.A.dylib 0x00007fff50b97b20 objc_exception_throw + 48
2 Runner 0x000000010e83f8b5 _ZN8firebase9firestore4util16ObjcThrowHandlerENS1_13ExceptionTypeEPKcS4_iRKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE + 581
3 Runner 0x000000010e83edf3 _ZN8firebase9firestore4util5ThrowENS1_13ExceptionTypeEPKcS4_iRKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE + 67
4 Runner 0x000000010e890589 _ZN8firebase9firestore4util20ThrowInvalidArgumentIJEEEvPKcDpRKT_ + 57
5 Runner 0x000000010e959f65 -[FSTUserDataConverter parseData:context:] + 1045
6 Runner 0x000000010e<…>
Lost connection to device.
I am running cloud_firestore: ^0.13.0+1 (currently the latest version) in the pubspec.yaml file. Everything is fine when running the flutter doctor command as well.
What am I doing wrong? Is it even possible to store matrixes in Firestore? If not, can I store that data using another logic?
While you can store an array in Firestore, as mentioned in the documentation, you are not allowed to store another array inside it.
You could take an approach where you store the arrays as fields in a document so you can actually keep each array separated. This is shown over at this thread, or this one.
Hope you find this useful!
The following approach will work for the Matrix you gave as an example, but you won't be able to query the matrix directly from Firestore. You must take the whole matrix out, parse it, and then use it:
final List<List<int>> myMatrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];
// Encode your matrix into a JSON String to add to Firestore
String jsonMatrix = jsonEncode(myMatrix);
// Decode your Json String into a JSON object
var decodedMatrix = jsonDecode(jsonMatrix);
// Decode JSON object back into your matrix
List<List<int>> newList = List<List<int>>.from(decodedMatrix.map((row){
return List<int>.from(row.map((value) => int.parse(value.toString())));
}));
// Print to show that the new object is of the same type as the original Matrix
print(newList is List<List<int>>);
I ended up making the following helper that converts the matrix into a map that's compatible with Firestore:
class MatrixHelper {
// Creates a map that can be stored in Firebase from an int matrix.
static Map<String, dynamic> mapFromIntMatrix(List<List<int>> intMatrix) {
Map<String, Map<String, dynamic>> map = {};
int index = 0;
for (List<int> row in intMatrix) {
map.addEntries([MapEntry(index.toString(), {})]);
for (int value in row) {
map[index.toString()].addEntries(
[MapEntry(value.toString(), true)]
);
}
index += 1;
}
return map;
}
// Creates an int matrix from a dynamic map.
static List<List<int>> intMatrixFromMap(Map<dynamic, dynamic> dynamicMap) {
final map = Map<String, dynamic>.from(dynamicMap);
List<List<int>> matrix = [];
map.forEach((stringIndex, value) {
Map<String, dynamic> rowMap = Map<String, dynamic>.from(value);
List<int> row = [];
rowMap.forEach((stringNumber, boolean) {
row.add(int.parse(stringNumber));
});
matrix.add(row);
});
return matrix;
}
}
It's really simple to use, to save in Firestore it's like this:
final List<List<int>> myMatrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];
await Firestore.instance.collection("anyCollection").add({
"matrix" : MatrixHelper.mapFromIntMatrix(myMatrix),
});
To load the matrix from Firestore, it's like this:
// Loads the DocumentSnapshot:
final document = await Firestore.instance.collection("anyCollection").document("anyDocument").get();
// Retrieves the Matrix:
final List<List<int>> matrix = MatrixHelper.intMatrixFromMap(document.data["matrix"]);

Flutter Odoo : how to read all fields

iam making a flutter app that depending on odoo
and i want to get all fields in a module
so iam using read method
and iam depending on this library
http://oogbox.com/page/odoo-api-flutter.html
https://pub.dartlang.org/packages/odoo_api/versions/1.0.1
the problem is that i tried everything to get all ids
i changed the List ids to []
and to null
and nothing working
and this is the code
final ids = [1, 2, 3, 4, 5];
final fields = ["id", "name", "email"];
client.read("res.partner", ids, fields).then((OdooResponse result) {
if (!result.hasError()) {
List records = result.getResult();
} else {
print (result.getError());
}
});
From the documentation this read method doesn't allow you to bring all records, you should use searchRead() and pass to the domain param an empty list to do that.

Algolia filter equivalent to SQL IN for arrays?

I've got records in Algolia containing an array attribute with integer values, like :
{
...
choice_ids: [1, 99, 100, 200]
...
}
I want to filter all records containing any value of another array. For example I search for [1, 300, 400, 600, 700], I should get the record on top because it contains 1.
Should I construct the filter with OR arguments or is there a better way?
Should I construct the filter with OR arguments or is there a better way?
Yes that's the way to go.
index.search('....', { filters: '(choice_ids=1 OR choice_ids=99 OR choice_ids=100 OR choice_ids=200)' });
For me it wasn't working with '=' but with ':', meaning:
{ filters: 'choice_ids:1 OR choice_ids:99 OR choice_ids:100 OR choice_ids:200' })
For me, neither of #Léo Chaz Maltrait or #redox answers worked. I had to format mine like:
{ filters: '(choice_ids:"1") OR (choice_ids:"99" OR (choice_ids:"100") OR (choice_ids:"200"))' })
I am also using algoliasearch npm package.

group and aggregate with rxjs

Scan works like this(with sum function):
1-1-1-1-1-1 -> 1-2-3-4-5-6
but I need something like this: with n=3
1-1-1-1-1-1 -> 3-3
How do I achieve this behavior?
In RxJs you can use bufferWithCount:
var source = Rx.Observable.from([1,1,1,1,1,1])
.bufferWithCount(3)
.flatMap(group => Rx.Observable.from(group).sum());
You could optionally use windowWithCount so that you don't have to rewrap the output in order to use sum but you'll also get an empty final window as well, which will fire out an extraneous 0 value.
This works in c#:
var query =
new [] { 1, 1, 1, 1, 1, 1, }
.ToObservable()
.Buffer(3)
.Select(x => x.Sum());
I assume [rxjs] would work similarly.