How to get the value of flutter map by call by value - flutter

I am developing a movie app using TMDB.
A total of 3 pieces of data are needed to create a reservation system.
1.MovieList's index
2.date's index
3.seat Satus
I've been trying to process this as a map.
//Seat Status total 200 Seat
List<bool> _seat = [];
for(int nIndex=0; nIndex<200; nIndex++){
_seat.add(false);
}
//Date index(total 7 days) + Seat status
Map _date = Map();
for(int nIndex=0; nIndex<7; nIndex++){
_date[nIndex] = _seat.toList();
}
//TMDB MovieList index
Map _movie = Map();
for(int nIndex=0; nIndex<MoviesList.length; nIndex++){
_movie[nIndex] = _date;
}
The value is entered normally as I want.
However, when one seat data is changed, all seat data in the map is changed.
I noticed that this is because the map and list references are input.
Do you know how to get a value by call by value rather than by call by reference?
seat = List.filled(200, false, growable: true);
date = List.generate(7, (_) => List.from(seat));
movie = List.generate(length, (_) => List.from(date));
My code was like above.
for example
movie[0][0][0] = false; // Change value
print(movie[0][0][0]); // result false
print(movie[1][0][0]); // result false
In this way, the values ​​change together.

In order to make a new list reference with the same values as the previous one, you can call List.from.
So like this:
_date[nIndex] = List.from(_seat);
you can use a similar syntax with a map
_movie[nIndex] = Map.from(_date);
EDIT
It seems like this solution actually does not work, dart can use .from to copy a list, or even to copy a list of lists, but copying a list of a list of lists? That's too much man! It can't handle that, it will only copy up one level. Thankfully, solving this is simple once you know why it happens:
var seat = List.filled(3, false, growable: true);
var date = List.generate(4, (_) => List.from(seat));
var movie = List.generate(5, (_) => List.from(date.map((v) =>
List.from(v))));
movie[0][0][0] = true; // Change value
print(movie[0][0][0]); // true
print(movie[1][0][0]); // false (default value)
For the last one, instead of creating a new list from seat, I am first using map to copy each of the lists on to a new list, and then I am copying those new lists into a new list.
I believe that fixes the issue we were encountering
PS
This is a recommendation, if you don't care, you can stop reading now:
if you want to generate a list of 200 false values, you can use this syntax instead:
List<bool> _seat = List.filled(200, false, growable: true);
which makes for a shorter and more readable way to do the same thing.
When declaring a map, this syntax is preferred:
Map<int, List<bool>> _date = {};
Map<int, Map<int, List<bool>>> _movie = {};
I know it looks a bit gross, but it makes sure you don't add the wrong types to your map
And finally, why are you using a map in the first place? Your map behaves the exact same as a list because the key is an index, and you could generate said list using the generate constructor instead of a for loop, like this:
//Date index(total 7 days) + Seat status
List<List<bool>> _date = List.generate(7, (_) => List.from(_seat));
//TMDB MovieList index
List<List<List<bool>>> _movie = List.generate(
MoviesList.length, (_) => List.from(_date));
Again, the syntax looks gross, that's because of all of the nested lists, probably better off making a class that can store the values in a more neat and type-safe way, but I lack the information to show you how you would write such a class.

Related

Filter list with whereIn condition in Flutter?

This code sample works fine.
var box = await Hive.openBox<MainWords>('mainWords');
box.values.where((item) {
return item.category == "6" || item.category == '13';
}).toList();
I am trying to filter a list with whereIn condition but it must filter like
List<String> categoryList = ['6', '13'];
var box = await Hive.openBox<MainWords>('mainWords');
box.values.where((item) {
return item in categoryList; // just an examle
}).toList();
How can i achive this?
You should not use the keyword in but the method contains to check if your item exists inside categoryList. Moreover you cannot compare values of different types, I'm seeing that you are returning with box.values an Iterable<MainWords>.
I don't know the content of this class but the item variable is of type MainWords and so it cannot be compared with a String object directly.
I am supposing that you have some access to a String value from your class MainWords so you will need to compare this value with your list.
Code Sample
List<String> categoryList = ['6', '13'];
var box = await Hive.openBox<MainWords>('mainWords');
// As I don't know what are MainWords' properties I named it stringValue.
box.values.where((item) => categoryList.contains(item.stringValue)).toList();

Dart / Flutter : Waiting for a loop to be completed before continuing... (Async Await?)

I have a function which creates a sublist from a large(very large list). After creating this list, the function goes on treating it (deleting duplicates, sorting...).
As long as the list was not too big, it worked fine. But now, I get "The Getter length was called on null". I suppose, it's because the second part of the function (after the loop) starts before the sublist is completed... so it doesn't work...
How can we force the function to wait for the loop to be over to continue the rest of the treatment ?
Is it with Async /Await ? Or can we do something like "While... something is not over...", or "As soon as something is done... do that" ? (My suggestions might be naive, but I am a beginner...)
Here is the code :
List themeBankFr() {
List<Map> themeBankFr = [];
for (Word word in wordBank) {
for (Thematique wordTheme in word.theme) {
themeBankFr.add({
'themeFr': wordTheme.themeFr,
'image': wordTheme.image,
});
}
}
// convert each item to a string by using JSON encoding
final jsonList = themeBankFr.map((item) => jsonEncode(item)).toList();
// using toSet - toList strategy
final uniqueJsonList = jsonList.toSet().toList();
// convert each item back to the original form using JSON decoding
final result = uniqueJsonList.map((item) => jsonDecode(item)).toList();
// sort the list of map in alphabetical order
result.sort((m1, m2) {
var r = m1['themeFr'].compareTo(m2['themeFr']);
if (r != 0) return r;
return m1['image'].compareTo(m2['image']);
});
return result;
}
i think i have a good answer that may helps you and it will as following
first create another function to do the work of for loops and this function returns a future of list that you need like below
Future<List<Map>> futureList(List wordBank){
List<Map> themeBankFr = [];
for (Word word in wordBank) {
for (Thematique wordTheme in word.theme) {
themeBankFr.add({
'themeFr': wordTheme.themeFr,
'image': wordTheme.image,
});
}
}
return Future.value(themeBankFr);
}
after that you can use this function inside your code and use it as async await and now you will never run the below lines before you return this array like below
List themeBankFr() async {
List<Map> themeBankFr = await futureList(wordBank);
// convert each item to a string by using JSON encoding
final jsonList = themeBankFr.map((item) => jsonEncode(item)).toList();
// using toSet - toList strategy
final uniqueJsonList = jsonList.toSet().toList();
// convert each item back to the original form using JSON decoding
final result = uniqueJsonList.map((item) => jsonDecode(item)).toList();
// sort the list of map in alphabetical order
result.sort((m1, m2) {
var r = m1['themeFr'].compareTo(m2['themeFr']);
if (r != 0) return r;
return m1['image'].compareTo(m2['image']);
});
return result;
}
i think this will solve your problem and i hope this useful for you

Flutter/Dart Compare multiple Lists and generate list with elements containd in all given lists

So here is my problem:
let's say we have two or more lists
List<SomeModel> one = [SomeModel, SomeModel, SomeModel],
List<SomeModel> two = [SomeModel, SomeModel, SomeModel, SomeModel, SomeModel, SomeModel]
what I want to do is compare these two/or more lists and make a new Listcontaining only those elements that exist in every list.
List<Fruits> one = [Banana, Apple, Cherry];
List<Fruits> two = [Cherry, Blueberry, Apple, Mango, Pineapple, Pear];
List<Fruits> three = [Cherry, Apple, Mango, Pineapple, Pear, Banana];
List<Fruits> getMatchingList(){
do something...
List<Fruits> matchingFruits = [Cherry, Apple];
return matchingFruits
}
I literally have no idea how to do this, especially with larger lists or with lists of unknown content.
If the number of lists is fixed you can just use the where function to filter items:
List<SomeModel> filteredList = one.where(item => two.contains(item))
.where(item => three.contains(item)).toList();
So your method will be:
List<Fruits> getMatchingList(List<Fruits> one, List<Fruits> two, List<Fruits> three){
return one.where(item => two.contains(item))
.where(item => three.contains(item))
.toList();
}
If you need an increasing number of lists to be processed, on the other side, just use:
List<Fruits> getMatchingList(List<List<Fruits>> listsToAnalyze){
Map<Fruits,integer> fruitCounter = new Map();
//expand is a method that flattern a list of lists in a single list
listsToAnalyze.expand(element => element).toList().forEach(element => {
//if the element exists, its counter is increased, otherwise is set to 1
fruitCounter.update(element, (count) => count+1, ()=> 1);
}
//remove results with counter < size of the list of lists
//supposing that an item can appear only once in each list, this means
//that the value appeared in all lists
fruitCounter.removeWhere((key,value)=> value<listsToAnalyze.lenght);
return fruitCounter.keys.toList();
}
In case an item can appear multiple times in a single list, do not expand the list and keep a List<Fruit> to control if an item was already inserted during each cycle on a list. Remember to empty the map at each new list.
List<Fruits> getMatchingList(List<List<Fruits>> listsToAnalyze){
Map<Fruits,integer> fruitCounter = new Map();
List<Fruits> fruitsInsertedThisRound= new List();
//cycle on each list alone
listsToAnalize.forEach(list => {
fruitsInsertedThisRound.clear(); //ensure that the list is empty at each cycle
list.forEach(el => {
//if the element exists, its counter is increased, otherwise is set to 1
if(!fruitsInsertedThisRound.contains(el){
//fruit still not inserted this round
fruitCounter.update(el, (count) => count+1, ()=> 1);
fruitsInsertedThisRound.add(el); //add the element to the list of inserted fruits
}
}
}
//remove results with counter < size of the list of lists
//this means that the value appeared in all lists
fruitCounter.removeWhere((key,value)=> value<listsToAnalyze.lenght);
return fruitCounter.keys.toList();
}
Merge both the list by removing duplicate
As Single Line
a.addAll(b.takeWhile((item)=> !a.contains(item)));
by looping
for(var item in a){
if(!b.contains(item)){
b.add(item);
}
}

How to shuffling the order of a list from snapshot.docs from Stream in firestore [duplicate]

I'm looking every where on the web (dart website, stackoverflow, forums, etc), and I can't find my answer.
So there is my problem: I need to write a function, that print a random sort of a list, witch is provided as an argument. : In dart as well.
I try with maps, with Sets, with list ... I try the method with assert, with sort, I look at random method with Math on dart librabry ... nothing can do what I wana do.
Can some one help me with this?
Here some draft:
var element03 = query('#exercice03');
var uneliste03 = {'01':'Jean', '02':'Maximilien', '03':'Brigitte', '04':'Sonia', '05':'Jean-Pierre', '06':'Sandra'};
var alluneliste03 = new Map.from(uneliste03);
assert(uneliste03 != alluneliste03);
print(alluneliste03);
var ingredients = new Set();
ingredients.addAll(['Jean', 'Maximilien', 'Brigitte', 'Sonia', 'Jean-Pierre', 'Sandra']);
var alluneliste03 = new Map.from(ingredients);
assert(ingredients != alluneliste03);
//assert(ingredients.length == 4);
print(ingredients);
var fruits = <String>['bananas', 'apples', 'oranges'];
fruits.sort();
print(fruits);
There is a shuffle method in the List class. The methods shuffles the list in place. You can call it without an argument or provide a random number generator instance:
var list = ['a', 'b', 'c', 'd'];
list.shuffle();
print('$list');
The collection package comes with a shuffle function/extension that also supports specifying a sub range to shuffle:
void shuffle (
List list,
[int start = 0,
int end]
)
Here is a basic shuffle function. Note that the resulting shuffle is not cryptographically strong. It uses Dart's Random class, which produces pseudorandom data not suitable for cryptographic use.
import 'dart:math';
List shuffle(List items) {
var random = new Random();
// Go through all elements.
for (var i = items.length - 1; i > 0; i--) {
// Pick a pseudorandom number according to the list length
var n = random.nextInt(i + 1);
var temp = items[i];
items[i] = items[n];
items[n] = temp;
}
return items;
}
main() {
var items = ['foo', 'bar', 'baz', 'qux'];
print(shuffle(items));
}
You can use shuffle() with 2 dots like Vinoth Vino said.
List cities = ["Ankara","London","Paris"];
List mixed = cities..shuffle();
print(mixed);
// [London, Paris, Ankara]

Using Reactive to sum the certain sections of Observable

I am trying to use reactive operators to find individual sum of the values emitted by the observable. The end goal is to emit individual sums. The sequence looks something like this. The ones I want to add up are occuring as continuous groups (of varying length) with varying frequency in between the values I want to discard. The ones I want to add have a field which is of type bool and has value true.
-(F,2)-(T,4)-(T,2)-(T,7)-(F,8)-(F,9)-(F,1)-(T,2)-(T,1)-(F,1)-
What have I tried so far:
myObservable.
.Where(x => x.IsItUseful == true)
.Aggregate(0.0, (sum,currentItem) => sum + currentItem.Value)
.Subscribe("NotYet")
This one give back the sum of ALL elements which have been marked as true.
myObservable
.SkipWhile(x => x.IsItUseful == false)
.TakeWhile(x => x.IsItUseful == true)
.Aggregate(0.0, (sum, currentItem) => sum + currentItem.Item3)
.Subscribe("NotYetAgain");
This one gives the sum of the first group only.
Right now I am trying along these lines.
myObservable
.Buffer(myObservable.DistinctUntilChanged(x => x.IsItUseful => true)
.Subscribe("NotSure")
I am still hazy on on BufferBoundary and BufferClosingSelector. I think a new buffer will open once I process a group of valid values. And this new buffer will have values from that point on wards till the end of another valid group. This means that I will pick up some not valid values too before the second group. I haven't been able to find some examples on Buffer with both open and close options getting used. Not sure if this is right approach too.
The final option is that I write an extension method on Buffer and put my custom logic there. But if there is an out of box solution I will prefer that.
There's two primary approaches I would recommend here. One uses Scan, the other uses Buffer/Window. Both of them have edge case problems that are solvable, but need clarity on the problem side.
Here's the Scan solution:
var result = source
.Scan((0, true), (state, value) => (value.IsItUseful ? state.Item1 + value.Value : 0, value.IsItUseful))
.Publish(_tuples =>
_tuples.Zip(_tuples.Skip(1), (oldTuple, newTuple) => (oldTuple, newTuple))
)
.Where(t => t.oldTuple.Item2 == true && t.newTuple.Item2 == false)
.Select(t => t.oldTuple.Item1);
Scan is similar to Aggregate, just more useful: Aggregate will only dump out one value at the end; whereas Scan emits intermediate values. So we track the running sum in there, resetting to 0 when we see a false. The next step (Zip) combines the latest message with its predecessor, so we can figure out whether or not we have to emit: We want to emit if the new flag value is false, but the old flag value is true. We then emit the old sum.
There's an edge case problem here if the last flag value is true: I'm assuming you want to emit on the OnCompleted, but that won't currently happen. Please clarify if that's needed.
Here's the Window solution:
var result2 = source
.Publish(_values => _values
.Window(_values.Select(v => v.IsItUseful).DistinctUntilChanged().Where(b => b == false))
)
.SelectMany(o => o.Where(a => a.IsItUseful).Sum(a => a.Value));
Window by the distinctly new falses, then sum them, similar to what you proposed.
The edge case problem here is that you end up with a leading and tailing 0 if you begin/end with falses (as your sample set does). Removing those would require some clean up as well.
FYI: Window and Buffer are practically the same: They have the same overloads and each group values into "windows". Window returns them as an observable stream, and Buffer holds them into a list which returns when the window closes. For more look here.
Here's runner code if anybody else wants to test this:
public class Message
{
public Message(bool b, int v)
{
IsItUseful = b;
Value = v;
}
public bool IsItUseful { get; set; }
public int Value { get; set; }
}
var values = new List<Message>
{
new Message(false, 2),
new Message(true, 4),
new Message(true, 2),
new Message(true, 7),
new Message(false, 8),
new Message(false, 9),
new Message(false, 1),
new Message(true, 2),
new Message(true, 1),
new Message(false, 1),
};
var source = values.ToObservable();
var result = source
.Scan((0, true), (state, value) => (value.IsItUseful ? state.Item1 + value.Value : 0, value.IsItUseful))
.Publish(_tuples =>
_tuples.Zip(_tuples.Skip(1), (oldTuple, newTuple) => (oldTuple, newTuple))
)
.Where(t => t.oldTuple.Item2 == true && t.newTuple.Item2 == false)
.Select(t => t.oldTuple.Item1);
var result2 = source
.Publish(_values => _values
.Buffer(_values.Select(v => v.IsItUseful).DistinctUntilChanged().Where(b => b == false))
)
.Select(o => o.Where(a => a.IsItUseful).Sum(a => a.Value));
result.Dump(); //Linqpad
result2.Dump(); //Linqpad