I want to get something like this:
[list1, list2].map( (var1, var2) => do something with var1;
do something with var2)
I tried:
List<int> counts = [1,2,3];
List<String> strings = ['','2',''];
print([counts, strings].map((list) => list[0].isEven; list[1].lenght))
IterableZip from package:collection should help.
https://pub.dartlang.org/documentation/collection/latest/collection/IterableZip-class.html
IterableZip([list1, list2]).map((values) {
doSomethingWith(values[0]);
doSomethingWith(values[1]);
});
It sounds like https://pub.dartlang.org/documentation/async/latest/async/StreamZip-class.html is what you want.
First convert list1 and list2 into their own individual streams, and then use StreamZip to combine both streams.
This for example will turn both values into a stream of strings containing both values:
StreamZip([list1, list2]).map((valuePair) => "${valuePair[0]}, ${valuePair[1]}"));
Sounds like you want the zip function which dart doesn't provide by default. A quick implementation would be something like this:
List<T3> zipList<T1, T2, T3>(List<T1> l1, List<T2> l2, T3 Function(T1, T2) zipper) {
if (l1.isEmpty) throw ArgumentError.value(l1, "l1", "input list cannot be empty");
if (l1.length != l2.length) throw ArgumentError("Two lists must have the same length");
var result = List<T3>(l1.length);
for(var i = 0; i < l1.length; i++) {
result.add(zipper(l1[i], l2[i]));
}
return result;
}
// here a quick example of how to use it.
class Bar {
final int i;
final String s;
Bar(this.i, this.s);
#override
String toString() => "Bar: $i - $s";
}
void testZipList() {
var list1 = [1,2,3];
var list2 = ["", "2", ""];
var bars = zipList(list1, list2, (l1, l2) => Bar(l1, l2));
bars.forEach(print);
}
In addition to the zipList provided in the accepted answer, here is a listIterable that may be useful if you have iterables that are not lists, yet.
Iterable<T3> zipIterable<T1, T2, T3>(Iterable<T1> l1, Iterable<T2> l2, T3 Function(T1, T2) zipper) sync* {
var i1 = l1.iterator;
var i2 = l2.iterator;
while(true) {
var fin1 = !i1.moveNext();
var fin2 = !i2.moveNext();
if (fin1 != fin2) {
throw ArgumentError("Two iterables must have the same length");
}
if (fin1) {
return;
}
yield zipper(i1.current, i2.current);
}
}
Related
I have a list (in flutter):
loadedSummaryList = [
'BILD',
'DRIT',
'VIMN',
'WELT',
'FLUTTER',
'ALL'
];
, and I want to sort this list like:
['WELT', 'BILD', 'VIMN', 'DRIT', 'ALL', 'FLUTTER']
in other words, I want to sort the first four elements of the list always like 'WELT', 'BILD', 'VIMN', 'DRIT', and then alphabetically.
I tried it like this:
List<String> sortList = ['WELT', 'BILD', 'VIMN', 'DRIT'];
loadedSummaryList.sort(
(a, b) {
int aIntex = sortList.indexOf(a.name);
int bIntex = sortList.indexOf(b.name);
return aIntex.compareTo(bIntex);
},
);
which returns
['ALL', 'FLUTTER', 'WELT', 'BILD', 'VIMN', 'DRIT'];
but actually, I want to have it like:
['WELT', 'BILD', 'VIMN', 'DRIT', 'ALL', 'FLUTTER']
could someone help me, please?
thanks in advance
Just sort them and merge them into one.
void main() {
var all = <String>['BILD', 'DRIT', 'VIMN', 'WELT', 'FLUTTER', 'ALL'];
var sort = <String>['WELT', 'BILD', 'VIMN', 'DRIT'];
// It depends on how you want list sorting in the end result.
// You can sort both lists if you want.
all.sort();
//sort.sort();
var result = sort.followedBy(all).toSet().toList();
print(result); // [WELT, BILD, VIMN, DRIT, ALL, FLUTTER]
}
First thing, indexOf returns -1 when the element is not in the list, therefore it will put those in front. A solution for that is to change it to a higher number in that case.
Secondly, you also need to sort them alphabetically, which you don't do now. You can do that by doing a compareTo on the strings themselves in the case that the first compareTo returns 0.
final result:
loadedSummaryList.sort(
(a, b) {
int aIntex = sortList.indexOf(a);
int bIntex = sortList.indexOf(b);
if (aIntex == -1) aIntex = sortList.length;
if (bIntex == -1) bIntex = sortList.length;
var result = aIntex.compareTo(bIntex);
if (result != 0) {
return result;
} else {
return a.compareTo(b);
}
},
);
Here is my Dart code
var mp = new Map();
mp[[1,2]] = "Hi";
mp[[3,5]] = "sir";
mp.remove([3,5]);
print(mp);
Output here is null
How can i access value at mp[[3,5]]?
Two list instances containing the same elements is not equal to each other in Dart. This is the reason your example does not work.
If you want to create a Map which works like your example, you can use LinkedHashMap from dart:collection (basically the same when you are using Map()) to create an instance with its own definition of what it means for keys to be equal and how hashCode is calculated for a key.
So something like this if you want to have keys to be equal if the list contains the same elements in the same order. It should be noted it does not support nested lists:
import 'dart:collection';
void main() {
final mp = LinkedHashMap<List<int>, String>(
equals: (list1, list2) {
if (list1.length != list2.length) {
return false;
}
for (var i = 0; i < list1.length; i++) {
if (list1[i] != list2[i]) {
return false;
}
}
return true;
},
hashCode: Object.hashAll,
);
mp[[1, 2]] = "Hi";
mp[[3, 5]] = "sir";
mp.remove([3, 5]);
print(mp); // {[1, 2]: Hi}
}
I should also add that this is really an inefficient way to do use maps and I am highly recommend to never use List as keys in maps.
You add a list instance as a key to the Map object. You need the corresponding list instance to delete it again.
There are two ways to access
First;
final mp = {};
mp[[1,2]] = "Hi";
mp[[3,5]] = "sir";
mp.removeWhere((key, value) {
if(key is List){
return key.first == 3 && key[1] == 5;
}
return false;
});
Second;
final mp = {};
final key = [3, 5];
mp[[1,2]] = "Hi";
mp[key] = "sir";
mp.remove(key);
Map countries = {
"01": "USA",
"02": "United Kingdom",
"03": "China",
"04": "India",
"05": "Brazil",
"06": "Nepal",
"07": "Russia"
};
//method 1:
var _key = countries.keys.firstWhere((k)
=> countries[k] == 'Russia', orElse: () => null);
print(key); //output: 07
How can nested lists be declared in Kotlin?
I'm looking for something in the form of:
var nestedList:List = [1,[2,[3,null,4]],[null],5]
so that I can flatten it later on (result should be nestedList = [1, 2, 3, 4, 5]).
If you have nested arrays structure (for instance, val array: Array<Array<out Int?>> = arrayOf(arrayOf(1), arrayOf(2), arrayOf(3, null, 4))), you can just use flatten extension method:
println(array.flatten().filterNotNull())
All common collections can't maintain variable layers count, so with them you can make only something like Andrey Ilyunin wrote - val array: Array<Array<out Int?>>.
But I wrote class structure to help you with your goal. It is no another collection and you can't work with it like it is, but it can make any layers amount you want. It is totally generic, so you can put there not only Int.
First of all, we start with NestedArrayItem class, which represents single item or one more nested array:
class NestedArrayItem<T> {
private val array: ArrayList<NestedArrayItem<T>>?
private val singleItem: T?
constructor(array: ArrayList<NestedArrayItem<T>>) {
this.array = array
singleItem = null
}
constructor(singleItem: T?) {
this.singleItem = singleItem
array = null
}
fun asSequence(): Sequence<T?> =
array?.asSequence()?.flatMap { it.asSequence() } ?:
sequenceOf(singleItem)
override fun toString() =
array?.joinToString(prefix = "[", postfix = "]") ?:
singleItem?.toString() ?: "null"
}
Then class NestedArray that is just like top level container for all the layers:
class NestedArray<T> {
private val array: ArrayList<NestedArrayItem<T>> = arrayListOf()
fun add(value: T?) {
array.add(NestedArrayItem(value))
}
fun addNested(nestedArray: NestedArray<T>) {
array.add(NestedArrayItem(nestedArray.array))
}
fun flatten(): ArrayList<T?> = array.asSequence()
.flatMap { it.asSequence() }
.toCollection(arrayListOf())
override fun toString() = array.joinToString(prefix = "[", postfix = "]")
}
And to make it easier to write values I additionally wrote builder class for that:
class NestedArrayBuilder<T> private constructor(private val result: NestedArray<T>){
constructor(fillNestedBuilder: NestedArrayBuilder<T>.() -> Unit) : this(NestedArray()) {
NestedArrayBuilder(result).apply(fillNestedBuilder)
}
fun add(value: T?): NestedArrayBuilder<T> {
result.add(value)
return this
}
fun addArray(fillNestedBuilder: NestedArrayBuilder<T>.() -> Unit): NestedArrayBuilder<T> {
val nestedResult = NestedArray<T>()
val nestedArray = NestedArrayBuilder(nestedResult).apply(fillNestedBuilder)
.build()
result.addNested(nestedArray)
return this
}
fun build() = result
}
That's it! You can use it. I put here example how to use it:
val array = NestedArrayBuilder<Int> {
add(1)
addArray {
add(2)
addArray {
add(3)
add(null)
add(4)
}
}
addArray {
add(null)
}
add(5)
}.build()
assertEquals("[1, [2, [3, null, 4]], [null], 5]", array.toString())
assertEquals(arrayListOf(1, 2, 3, null, 4, null, 5), array.flatten())
With the following code:
public class Main {
public static void main(String[] args) {
final List<Integer> items =
IntStream.rangeClosed(0, 23).boxed().collect(Collectors.toList());
final String s = items
.stream()
.map(Object::toString)
.collect(Collectors.joining(","))
.toString()
.concat(".");
System.out.println(s);
}
}
I get:
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23.
What I would like to do, is to break the line every 10 items, in order to get:
0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,19,
20,21,22,23.
I have try a lot of things after googling without any success !
Can you help me ?
Thanks,
Olivier.
If you're open to using a third-party library, the following will work using Eclipse Collections Collectors2.chunk(int).
String s = IntStream.rangeClosed(0, 23)
.boxed()
.collect(Collectors2.chunk(10))
.collectWith(MutableList::makeString, ",")
.makeString("", ",\n", ".");
The result of Collectors2.chunk(10) will be a MutableList<MutableList<Integer>>. At this point I switch from the Streams APIs to using native Eclipse Collections APIs which are available directly on the collections. The method makeString is similar to Collectors.joining(). The method collectWith is like Stream.map() with the difference that a Function2 and an extra parameter are passed to the method. This allows a method reference to be used here instead of a lambda. The equivalent lambda would be list -> list.makeString(",").
If you use just Eclipse Collections APIs, this problem can be simplified as follows:
String s = Interval.zeroTo(23)
.chunk(10)
.collectWith(RichIterable::makeString, ",")
.makeString("", ",\n", ".");
Note: I am a committer for Eclipse Collections.
If all you want to do is process these ascending numbers, you can do it like
String s = IntStream.rangeClosed(0, 23).boxed()
.collect(Collectors.groupingBy(i -> i/10, LinkedHashMap::new,
Collectors.mapping(Object::toString, Collectors.joining(","))))
.values().stream()
.collect(Collectors.joining(",\n", "", "."));
This solution can be adapted to work on an arbitrary random access list as well, e.g.
List<Integer> items = IntStream.rangeClosed(0, 23).boxed().collect(Collectors.toList());
String s = IntStream.range(0, items.size()).boxed()
.collect(Collectors.groupingBy(i -> i/10, LinkedHashMap::new,
Collectors.mapping(ix -> items.get(ix).toString(), Collectors.joining(","))))
.values().stream()
.collect(Collectors.joining(",\n", "", "."));
However, there is no simple and elegant solution for arbitrary streams, a limitation which applies to all kind of tasks having a dependency to the element’s position.
Here is an adaptation of the already linked in the comments Collector:
private static Collector<String, ?, String> partitioning(int size) {
class Acc {
int count = 0;
List<List<String>> list = new ArrayList<>();
void add(String elem) {
int index = count++ / size;
if (index == list.size()) {
list.add(new ArrayList<>());
}
list.get(index).add(elem);
}
Acc merge(Acc right) {
List<String> lastLeftList = list.get(list.size() - 1);
List<String> firstRightList = right.list.get(0);
int lastLeftSize = lastLeftList.size();
int firstRightSize = firstRightList.size();
// they are both size, simply addAll will work
if (lastLeftSize + firstRightSize == 2 * size) {
System.out.println("Perfect!");
list.addAll(right.list);
return this;
}
// last and first from each chunk are merged "perfectly"
if (lastLeftSize + firstRightSize == size) {
System.out.println("Almost perfect");
int x = 0;
while (x < firstRightSize) {
lastLeftList.add(firstRightList.remove(x));
--firstRightSize;
}
right.list.remove(0);
list.addAll(right.list);
return this;
}
right.list.stream().flatMap(List::stream).forEach(this::add);
return this;
}
public String finisher() {
return list.stream().map(x -> x.stream().collect(Collectors.joining(",")))
.collect(Collectors.collectingAndThen(Collectors.joining(",\n"), x -> x + "."));
}
}
return Collector.of(Acc::new, Acc::add, Acc::merge, Acc::finisher);
}
And usage would be:
String result = IntStream.rangeClosed(0, 24)
.mapToObj(String::valueOf)
.collect(partitioning(10));
I have List List<MyType>, my type contains Age and RandomID
Now I want to find the maximum age from this list.
What is the simplest and most efficient way?
Assuming you have access to LINQ, and Age is an int (you may also try var maxAge - it is more likely to compile):
int maxAge = myTypes.Max(t => t.Age);
If you also need the RandomID (or the whole object), a quick solution is to use MaxBy from MoreLinq
MyType oldest = myTypes.MaxBy(t => t.Age);
Okay, so if you don't have LINQ, you could hard-code it:
public int FindMaxAge(List<MyType> list)
{
if (list.Count == 0)
{
throw new InvalidOperationException("Empty list");
}
int maxAge = int.MinValue;
foreach (MyType type in list)
{
if (type.Age > maxAge)
{
maxAge = type.Age;
}
}
return maxAge;
}
Or you could write a more general version, reusable across lots of list types:
public int FindMaxValue<T>(List<T> list, Converter<T, int> projection)
{
if (list.Count == 0)
{
throw new InvalidOperationException("Empty list");
}
int maxValue = int.MinValue;
foreach (T item in list)
{
int value = projection(item);
if (value > maxValue)
{
maxValue = value;
}
}
return maxValue;
}
You can use this with:
// C# 2
int maxAge = FindMaxValue(list, delegate(MyType x) { return x.Age; });
// C# 3
int maxAge = FindMaxValue(list, x => x.Age);
Or you could use LINQBridge :)
In each case, you can return the if block with a simple call to Math.Max if you want. For example:
foreach (T item in list)
{
maxValue = Math.Max(maxValue, projection(item));
}
int max = myList.Max(r => r.Age);
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.max.aspx
var maxAge = list.Max(x => x.Age);
thelist.Max(e => e.age);
Easiest way is to use System.Linq as previously described
using System.Linq;
public int GetHighestValue(List<MyTypes> list)
{
return list.Count > 0 ? list.Max(t => t.Age) : 0; //could also return -1
}
This is also possible with a Dictionary
using System.Linq;
public int GetHighestValue(Dictionary<MyTypes, OtherType> obj)
{
return obj.Count > 0 ? obj.Max(t => t.Key.Age) : 0; //could also return -1
}
Simplest is actually just Age.Max(), you don't need any more code.
How about this way:
List<int> myList = new List<int>(){1, 2, 3, 4}; //or any other type
myList.Sort();
int greatestValue = myList[ myList.Count - 1 ];
You basically let the Sort() method to do the job for you instead of writing your own method. Unless you don't want to sort your collection.