I'm trying to create a copy/clone of a "List<List<Map'>>".
So far I tried:
dataFTY2 = dataFTY.map((element)=>element).toList();
dataFTY2 = json.decode(json.encode(dataFTY));
dataFTY2 = List.from(dataFTY);
Nothing seems to work. Whenever I change the copy "dataFTY2", dataFTY changes as well. I need this to be a completely independent copy. Please help. I cant seem to figure this out, its driving me crazy.
More code added for reference.
List failureDetails = [];
List trackIDs = [];
List dateTime = [];
var dataFTY2 = dataFTY.map((element) => element.map((ele) => Map.from(ele)).toList()).toList();
// get historyData for each one and sort through "F"s and put them into the table in a row?
for (var x in dataFTY2[4]) {
trackIDs.add(x["track_id"]);
dateTime.add(x["datetime"]);
}
List failuresOnly = List.filled(trackIDs.length, {}, growable: true);
for (var i = 0; i < trackIDs.length; i++) {
await fetchTrackIDTestDetails(context, trackIDs[i], dateTime[i], false);
failureDetails.add(MyGlobals().getTestCodeDetailsData());
}
//filter out only "F"s
for (var p = 0; p < failureDetails.length; p++) {
for (var t in failureDetails[p][0]) {
if (t["Status"] == "F") {
//add it to list, if pass do nothing
failuresOnly[p] = t;
}
}
}
//combine with FTY failure data, don't use new screen use old screen and toggle when pressed, add column on right side
//dataFTY2 = MyGlobals().getFTYFailureMoreDetails();
for (var i = 0; i < dataFTY2[4].length; i++) {
dataFTY2[4][i]["TestCode"] = failuresOnly[i]["TestCode"];
dataFTY2[4][i]["Status"] = failuresOnly[i]["Status"];
dataFTY2[4][i]["TestValue"] = failuresOnly[i]["TestValue"];
dataFTY2[4][i]["Lo_Limit"] = failuresOnly[i]["Lo_Limit"];
dataFTY2[4][i]["Up_Limit"] = failuresOnly[i]["Up_Limit"];
dataFTY2[4][i]["ProcTime"] = failuresOnly[i]["ProcTime"];
}
You can use Map.from named constructor to clone the Map like this,
dataFTY2 = dataFTY.map((element) => element.map((ele) => Map.from(ele)).toList()).toList();
I find it more straightforward to use collection-for and the spread (...) operator:
void main() {
var original = [
[
{'foo': 1, 'bar': 2},
{'foo': 3, 'bar': 4},
]
];
// Create a new List...
var copy = [
for (var sublist in original)
// ... where each element is a new List...
[
for (var map in sublist)
// ... where each element of the sublist is a new Map that
// copies all entries from `map`.
{...map},
],
];
original[0][0]['foo'] = -1;
print(original); // Prints: [[{foo: -1, bar: 2}, {foo: 3, bar: 4}]]
print(copy); // Prints: [[{foo: 1, bar: 2}, {foo: 3, bar: 4}]]
}
Related
I want to improve on my current solution of putting values of hierarchical data structures together in a common list of maps. I'm looking for a more concise and more efficient solution, maybe one that does not use a nested for-loop.
Here's the code which includes the problem, a desired output and my current solution:
class Bar{
String someVal;
int num;
Bar(this.someVal, this.num);
}
class Foo{
String someVal;
List<Bar> bars;
Foo(this.someVal, this.bars);
}
void main()
{
Bar bar1 = Bar("val1", 3);
Bar bar2 = Bar("val2", 5);
Bar bar3 = Bar("val3", 2);
Foo foo1 = Foo("someString1", [bar1, bar2, bar3]);
Bar bar4 = Bar("val4", 2);
Bar bar5 = Bar("val5", 3);
Bar bar6 = Bar("val6", 1);
Foo foo2 = Foo("someString2", [bar4, bar5, bar6]);
// Given
List<Foo> foos = [foo1, foo2];
// Desired result:
List<Map> namedBars =
[{"someVal": "someString1", "bar": bar1},
{"someVal": "someString1", "bar": bar2},
{"someVal": "someString1", "bar": bar3},
{"someVal": "someString2", "bar": bar4},
{"someVal": "someString2", "bar": bar5},
{"someVal": "someString2", "bar": bar6},
];
// my current solution
final allBars = foos.map((foo) => foo.bars).expand((bar) => bar).toList();
var countsBar = foos.map((foo) => foo.bars.length).toList();
var namedBars = [];
var k = 0;
for(var i = 0; i < countsBar.length; i++){
for(var j = 0; j < countsBar[i]; j++){
namedBars.add({"someVal": foos[i].someVal,
"bar": allBars[k]});
k++;
}
}
Well written question with examples. Good solution by #pskink.
var pskinkSolution = foos
.expand((foo) => foo.bars.map((bar) => {
'someVal': foo.someVal,
'bar': bar,
}))
.toList();
Solution in DartPad:
https://dartpad.dev/?id=a4cade24fded7bf62025daa5879fb373
I have a list
final List list = [1, 2, 3, 4, 5, 6, 7];
how can I "map" to the output as a new List like:
"1 and 2",
"3 and 4",
"5 and 6",
"7"
You can achieve that using the following function:
_getComponents(list) => list.isEmpty ? list :
([list
.take(2)
.join(' and ')
]..addAll(_getComponents(list.skip(2))));
Call that function like:
List outPut = _getComponents(yourList);
Explanation:
You are declaring a recursive function called _getComponents
As the first statement you are checking whether the parameter list is empty, if it's empty returning the parameter as is
If the list is not empty
You are taking the first 2 items from the list using take function
You are joining those elements using join function
You are calling the addAll function and supplies the result of recursive _getComponents call as it's argument
And as the parameter of that _getComponents function you are passing the list, after skipping the first 2 elements using the skip function
Answer came off the top of my head but try this:
final List list = [1, 2, 3, 4, 5, 6, 7];
List<String> grouped = [];
for (int i = 0; i < list.length; i++) {
if (i % 2 == 0) {
if (i + 1 < list.length) {
grouped.add("${list[i]} and ${list[i + 1]}");
} else {
grouped.add("${list[i]}");
break;
}
}
}
print(grouped);
This works
main(){
final List list = [1,2,3,4,5,6,7];
final List newList = [];
for(int i = 0; i<list.length; i++){
var string;
if(i+1<list.length){
string = "${list[i]} and ${list[i+1]}";
i++;
}else{
string = "${list[i]}";
}
newList.add(string);
}
print(newList);
}
Write this:
void main(){
final List oldList = [1,2,3,4,5,6,7];
final List newList = [];
for(int i = 0; i<list.length; i += 2){
if(i+1<oldList.length){
newList.add("${oldList[i]} and ${oldList[i+1]}");
}else{
newList.add("${oldList[i]}");
}
}
print(newList);
}
How I can get the most popular number from a list in dart without using any third party libraries?
var list = [0, 1, 1, 2, 2, 2, 3, 3, 4]; // most popular number is 2
If there are two or more popular numbers then the output should be a List with both values. Example:
One popular number:
var list = [0, 1, 1, 2, 2, 2, 3, 3, 4];
// Output should be [2]
Two or more popular numbers:
var list = [0, 1, 1, 2, 2, 2, 3, 3, 3];
// Output should be [2, 3]
Thank you in advance for your help!
This works...you can optimize it
var list = [1, 1, 2, 2, 3, 4, 5];
list.sort();
var popularNumbers = [];
List<Map<dynamic, dynamic>> data = [];
var maxOccurrence = 0;
var i = 0;
while (i < list.length) {
var number = list[i];
var occurrence = 1;
for (int j = 0; j < list.length; j++) {
if (j == i) {
continue;
}
else if (number == list[j]) {
occurrence++;
}
}
list.removeWhere((it) => it == number);
data.add({number: occurrence});
if (maxOccurrence < occurrence) {
maxOccurrence = occurrence;
}
}
data.forEach((map) {
if (map[map.keys.toList()[0]] == maxOccurrence) {
popularNumbers.add(map.keys.toList()[0]);
}
});
print(popularNumbers);
try this to count each element in list:
var list = [0, 1, 1, 2, 2, 2, 3, 3, 4];
var popular = Map();
list.forEach((l) {
if(!popular.containsKey(l)) {
popular[l] = 1;
} else {
popular[l] +=1;
}
});
I guess I found the solution.
Let me explain it to you:
I had queried through your list and checked whether the keys of the map contains the element or not. If the map does not contain the element as the key then, it will create a key from the element and pass 1 as the value. If the map does contain the element as a key then it will simply increment the value.
Once the map is ready, I had sorted the map values and stored them in a List. From the sorted map values I had taken the last element from the list of sorted values because we had sorted it in ascending order so the most popular value will be at last.
At last, I had queried through the map and check whether the value of the particular key is equal to the popularValue or not. If it is then we are adding the current key and value to the mostPopularValues list.
If I got something wrong please let me know.
void main() {
List list = [0, 1, 1, 1, 2, 2, 2, 3, 3, 4];
List mostPopularValues = [];
var map = Map();
list.forEach((element) {
if (!map.containsKey(element)) {
map[element] = 1;
} else {
map[element] += 1;
}
});
print(map);
// o/p : {0: 1, 1: 3, 2: 3, 3: 2, 4: 1}
List sortedValues = map.values.toList()..sort();
print(sortedValues);
// o/p : [1, 1, 2, 3, 3]
int popularValue = sortedValues.last;
print(popularValue);
// o/p : 3
map.forEach((k, v) {
if (v == popularValue) {
mostPopularValues.add("$k occurs $v time in the list");
}
});
print(mostPopularValues);
// o/p : [1 occurs 3 time in the list, 2 occurs 3 time in the list]
}
Not sure if that's the best solution, but it works pretty well. Let me know if there are any doubts.
final list = [0, 1, 1, 2, 2, 2, 3, 3, 4];
// Count occurrences of each item
final folded = list.fold({}, (acc, curr) {
acc[curr] = (acc[curr] ?? 0) + 1;
return acc;
}) as Map<dynamic, dynamic>;
// Sort the keys (your values) by its occurrences
final sortedKeys = folded.keys
.toList()
..sort((a, b) => folded[b].compareTo(folded[a]));
print('Most popular value: ${sortedKeys.first}'); // 1
print('Second most popular value: ${sortedKeys[1]}'); // 2
I have solved this problem by defining an extension on Iterable:
extension MostPopularItemsExtension<E> on Iterable<E> {
/// Returns the most popular items, where all items in the returned
/// list have the same number of occurances. If [this] is empty, returns an
/// empty list
///
/// Examples:
/// `[1,2,3,2].mostPopularItems() == [2]`
/// `[1,1,2,2].mostPopularItems() == [1,2]`
Iterable<E> mostPopularItems() {
if (isEmpty) return [];
final itemsCounted = <E, int>{};
for (final e in this) {
if (itemsCounted.containsKey(e)) {
itemsCounted[e] = itemsCounted[e]! + 1;
} else {
itemsCounted[e] = 1;
}
}
final highestCount = (itemsCounted.values.toList()..sort()).last;
return itemsCounted.entries
.where((e) => e.value == highestCount)
.map((e) => e.key);
}
}
The basic idea is to count all occurrences of each item in a Map object, get the highest count from this map and then return all items that have that specific number of occurrences.
I found online soluton like this:
import 'package:queries/collections.dart';
void main() {
List<String> list = ["a", "a", "b", "c", "b", "d"];
var result = new Collection(list).distinct();
print(result.toList());
}
But, I don't know how to convert var result back to List<Widget>.
There is a way that is a lot easier and does not require any additional imports.
You can convert your List to a Set which inherently only contains distinct elements and then convert that Set back to a List.
If you are using Dart 2.3 or higher (environment: sdk: ">=2.3.0 <3.0.0"), you can use the following idiomatic version:
List<String> list = ['a', 'a', 'b', 'c', 'b', 'd'];
List result = [...{...list}];
The ... spread operator for iterables was just introduced with Dart 2.3.
Otherwise, you can just use old syntax:
List<String> list = ["a", "a", "b", "c", "b", "d"];
List result = list.toSet().toList();
Thank you for your answer,
Here is the full code, i try to modify your method but not working.
(Works only in print)
Future<List<List<Widget>>> getList(List<int> list, String column) async {
List<Widget> list1 = List();
List<Widget> list2 = List();
List<Widget> list3 = List();
//test
List<String> testlista = List();
testlista.add(result[0][column].toString());
List<List<Widget>> listFromDB = [list1, list2, list3];
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'books.db');
Database database = await openDatabase(path, version: 1);
for (int i = 0; i < list.length; i++) {
var result = await database.rawQuery(
'SELECT DISTINCT $column FROM planner WHERE id = ${list[i]}');
//here polulate new List
testlista.add(result[0][column].toString());
if (list[i] < 18) list1.add(_item(result[0][column].toString()));
if (list[i] > 17 && list[i] < 50)
list2.add(_item(result[0][column].toString()));
if (list[i] > 49) list3.add(_item(result[0][column].toString()));
}
//Now this give me corect print list without duplicate!!!
for (int i = 0; i < testlista.length-1; i++) {
print('FROM DELETE method: '+ deleteDuplicate(testlista)[i]);
}
await database.close();
return listFromDB;
}
//Method for removingDuplicate
List<String> deleteDuplicate(List<String> lista) {
// List<String> result = Set.from(lista).toList();
List<String> result = {...lista}.toList();
return result;
}
If I want to query users' age > 18,
and export result to corresponding collection,
How could I do it by rewriteing the following script?
The following is psuedo code
source_collections = ["user_1", "user_2", ..., "user_999"]
output_collections = ["result_1", "result_2", ..., "result_999"]
pipeline = [
{
"$match":{"age": > 18}
}
{ "$out" : output_collections }
]
cur = db[source_collections].runCommand('aggregate',
{pipeline: pipeline,allowDiskUse: true})
The script you're looking for is something like:
var prefix_source = 'user_';
var prefix_output = 'result_';
var source_collections = [];
var output_collections = [];
var numCollections = 999;
for (var i = 1; i <= numCollections; i++) {
source_collections.push(prefix_source + i);
output_collections.push(prefix_output + i);
}
var pipeline = [{'$match': {age: {'$gt': 18}}}, {'$out': ''}]; for (var currentCollection = 0; currentCollection < source_collections.length; currentCollection++) {
pipeline[pipeline.length - 1]['$out'] = output_collections[currentCollection];
var cur = db[source_collections[currentCollection]].runCommand('aggregate', {pipeline: pipeline,allowDiskUse: true});
}
And while you're at it, the var cur = ... line could be simplified to
db[source_collections[currentCollection]].aggregate(pipeline, {allowDiskUse: true});
Note: I've added a piece that generates your arrays for you, as I'm sure you're not looking to write them by hand :D