In this code snippet
void main() {
List<int> myList = List.generate(2, (_) => 0, growable: true);
myList.addAll(List<int>.generate(1, (_) => 0));
myList.insert(3, 11);
print(myList);
}
I generate a list with two elements. Then I add a list with one element to it. So in total the original list should have 3 elements. So why does an insert at index 3 (fourth element) work? I expect an out of range error as is the case with myList.insert(4, 11).
Debug Code:
List<int> myList = List.generate(2, (_) => null, growable: true);
print("the list before adding temp list: ${myList}");
myList.addAll(List<int>.generate(1, (_) => null, growable: true));
print("the list after adding temp list: ${myList}");
myList.insert(3, 11);
print("the list after inserting an element at index 3 of combined list: ${myList}");
Debug Output:
the list before adding temp list: [null, null]
the list after adding temp list: [null, null, null]
the list after inserting an element at index 3 of combined list: [null, null, null, 11]
That's just how insert works.
The index you provide is not an element position, but the position of a gap between elements - or before the first element or after the last.
So, a list of length 3 has four gaps, the |s of: |1|2|3|. These have positions 0 through 3, and you can insert an element in any of them.
Move your mouse to List.generate you will see the following:
The created list is fixed-length if [growable] is set to false.
As you are passing true value in growable so It will increase the length of array if you will pass value False then the behavior will be changed
growable: true, it will not throw error untill you pass invalid index for example if you write myList.insert(5, 11); without writting myList.insert(4, 11); then myList.insert(5, 11); will throw error
List<int> myList = List.generate(2, (_) => 0, growable: true);
myList.addAll(List<int>.generate(1, (index) => 0));
myList.insert(3, 11);
print(myList);
growable: false It will throw error on both addAll and insert
List<int> myList = List.generate(2, (_) => 0, growable: false);
myList.addAll(List<int>.generate(1, (index) => 0));
myList.insert(3, 11);
print(myList);
Run the above different code you see the different behaviour.
Related
I have searched a lot for removing duplicates from a list in Dart using ANOTHER variable.
Here is what I mean:
List<int> numbers = [1, 2, 3, 4];
// This list has 4 new elements than the first one
List<int> moreNumbers = [1, 2, 3, 4, 5, 6, 7, 8];
// Now I want to push the moreNumbers unique elements to the numbers one
I want to push it so the end result for the numbers variable should be:
[1, 2, 3, 4, 5, 6, 7, 8];
Is it possible?
void main() {
var lst = [1,2,3,4];
var lst2 = [1,2,3,4,5,6,7,8];
var s = {...(lst+lst2)};
print(s.toList());
}
The trivial approach would be:
for (var number in moreNumbers) {
if (!numbers.contains(number)) {
numbers.add(number);
}
}
Not particularly efficient if numbers is long, because contains on a list can take time proportional to the length of the list.
The time/space trade-off would be creating a set from numbers, because sets have cheap contains:
var alsoNumbers = numbers.toSet(); // Also linear, but only happens once.
for (var number in moreNumbers) {
if (alsoNumbers.add(number)) { // true if elements was added
numbers.add(number);
}
}
(Using add instead of contains ensures that you update the set with new values, so you won't add the same new value twice.)
If you could just make numbers a Set to begin with, it would be much easier to avoid duplicates, just do numbers.addAll(moreNumbers).
I want to know how this work it should remove the item in list number 3 which is 'four' and print 'one','two','Three' why it is print three, four
here is the code:
final numbers = <String>['one', 'two', 'three', 'four'];
numbers.removeWhere((item) => item.length == 3);
print(numbers); // [three, four]`
removeWhere :Removes all objects from this list that satisfy test.
An object o satisfies test if test(o) is true.
removeWhere will go through the list and find the matched item, means where we do our logic and return true.
You can see item.length==3 is true for 'one' and 'two' because its string length is 3, that's why these elements are removed. You can find more on List
You can expand the method like
numbers.removeWhere((item) {
bool isItemContains3Char = item.length == 3;
print("${isItemContains3Char} : $item length : ${item.length}");
return isItemContains3Char;
});
All you need to return true based on your logic from removeWhere to remove elements.
final numbers = <String>['one', 'two', 'three', 'four'];
numbers.removeAt(2);
print(numbers);
output
[one, two, four]
Is there a combination of Dart spread operators and null-aware operators that will do this?
[
1,
...twoOrNull() // this will be inserted only if it's null. something else than the ... operator will be here.
3,
]
So the list will be either [1, 2, 3] or [1, 3]. I guess twoOrNull() can return [2] or [], but it would be nice if it could return 2 or null.
Is this possible without introducing a variable?
There is a null-aware spread operator (...?), but your twoOrNull() function would have to return either [2]or null; the spread operator expands an iterable within another collection literal, and it doesn't make sense to "spread" an int.
There's also Dart's collection-if construct, but it would require either calling twoOrNull() twice or saving the result in a variable:
[
1,
if (twoOrNull() != null) twoOrNull(),
3,
]
See the Lists section from the Dart Language Tour for more information about spread and collection-if.
An one-liner without side effect:
[
1,
...[twoOrNull()]..removeWhere((x) => x == null),
3,
]
The idea here is to map from an int twoOrNull() to a list of either [2] or [], then use the spreading operator ... to unfold it.
Note that having one twoOrNull() in this case is fine, but as soon as you start having more elements that need null checking before being added to the list, readability will suffer. In that case, consider delaying the null check to after you have added the element to the list, i.e.
[
1,
twoOrNull(),
3,
]..removeWhere((x) => x == null)
This will make the code a lot more straightforward and readable.
EDIT:
For the best readability in the list, it would be perfect to have a twoOrNullList() function returning either [2] or []. Then you can use it pretty much similar to what you proposed:
var twoOrNullList() => [twoOrNull()]..removeWhere((x) => x == null)
[
1,
...twoOrNullList(),
3,
]
Yet another solution.
Iterable<T> emit<T>(T? p) sync* {
if (p != null) {
yield p;
}
}
[
1,
...emit(twoOrNull()),
3,
]
At the moment I have this list
List.generate(72, (index) {
retrun Container(
child: new Text('$index'),
)
})
as the children of a GridView widget. What I however would like to do is return a different value than the $index for certain index values.
For this I have a List that looks like [{index: 2, value: test}{index: 5, value: hello}] with a lot of index/value pairs. So here is the question:
Is there a way now to display the value from the list in the GridView field if the matching index is in the list and if it is not simply return $index?
Just as an example, the field with the index 1 in the GridView should display its index, so it displays 1. The field with the index 2 however should display the matching value from the list, which is test and so on.
It looks like you should preprocess the list into a Map. If necessary, iterate the list adding each entry to a map.
Then you can:
Map m = <int, String>{
2: 'test',
5: 'hello',
};
List<Container>.generate(72, (int index) {
String s = m[index];
return Container(
child: Text(s != null ? s : '$index'),
);
});
or, more succinctly with the null aware operator
List<Container>.generate(
72,
(int index) => Container(child: Text(m[index] ?? '$index')),
);
Is it possible to initialize a list on one line in Dart? Something like the following...
List<int> options = new List<int>{ 1,2,5,9 };
(this is possible in c# and is called a collection initializer)
Yes:
List<int> options = [1, 2, 5, 9];
I'd recommend reading:
https://api.dartlang.org/stable/1.24.3/dart-core/List-class.html
Yes, you can do it using the List.unmodifiable constructor:
var options = new List.unmodifiable([3,6,7,8]);
Or by using the List.from constructor:
var options = new List.from([3,6,7,8]);
Or just like this:
var options = [5,7,9,0];
There are also available List.filled and List.generate factory constructors:
List<int?> s = List.filled(5, 10, growable: true); // [10, 10, 10, 10, 10]
This creates list of length 5, of type int or null, and initializes each element with 10. This list is growable, which means its length can be changed with a setter:
s.length = 10;
s[8] = 2; // [10, 10, 10, 10, 10, null, null, null, 2, null]
After changing the list length, new elements will be initialized with null. If the list element type is not-nullable this will cause Exception.
List.generate generates a list of values.
var n = List.generate(5, (index) => 0); // [0, 0, 0, 0, 0]
The created list is fixed-length, and each element is set to 0.
List<int?> n = List.generate(5, (index) => index * index, growable: true); // // [0, 1, 4, 9, 16]
If we want to create growable list (i.e. we set growable to true) we need to explicitly choose non-nullable type eg. int? as we did here, otherwise increasing list length will raise exception. This stands for both List.generate and List.filled factories.
Good reads about those are:
https://api.dart.dev/stable/1.24.3/dart-core/List/List.generate.html
and
https://api.dart.dev/stable/1.24.3/dart-core/List/List.filled.html
var vals = <int>[1, 2, 3];
var vals2 = List<int>()..addAll([1, 2, 3]);
var vals3 = List<int>.of([1, 2, 3]);
Note that when we don't provide a type, we in fact create a list of a
dynamic type. Also, the new keyword is optional.
Square brackets define a List
var listOfInt = [1,2,3]
Curly brackets define a Set
var setOfInt = {1,2,3};
Curly brackets with colons define a Map
var mapOfIntString = {1: "a", 2: "b"};
It is possible to specify the type explicitly.
var list = <int>[1,2,3]
var setOfInt = <int>{1,2,3};`
var map = <int,String>{1: "a", 2: "b"};
Initialize empty list
List<int> options = [];
Initialize filled list
List<int> options = [1,2,5,9];