Что эквивалентно Scala groupBy в D? - PullRequest
2 голосов
/ 27 сентября 2019

Всякий раз, когда вы хотите создать частоту Map в Scala, вы можете легко вызвать .groupBy для коллекции.

val seq = Seq("a", "a", "b", "c", "b", "a")
seq.groupBy(a => a) // Map(b -> List(b, b), a -> List(a, a, a), c -> List(c))

То же самое легко сделать с вложенными коллекциями.

val nseq = Seq(Seq("a", 1), Seq("a", -1), Seq("b", -5), Seq("c", 100), Seq("b", 5), Seq("a", 0))
nseq.groupBy(a => a(0)) // Map(b -> List(List(b, -5), List(b, 5)), a -> List(List(a, 1), List(a, -1), List(a, 0)), c -> List(List(c, 100)))

Обратите внимание, как значения объединяются для каждого ключа.

Я попытался найти аналогичную функцию в D и нашел group.Он работает несколько иначе, так как возвращает пары кортежей.

int[] arr = [1, 1, 2, 2, 3, 2, 2, 5];
arr.sort.group; // [Tuple!(int, uint)(1, 2), Tuple!(int, uint)(2, 4), Tuple!(int, uint)(3, 1), Tuple!(int, uint)(5, 1)]
arr.sort.group.assocArray; // [5:1, 3:1, 2:4, 1:2]

Однако, когда речь идет о вложенных коллекциях.

Tuple!(string, int)[] arr = [tuple("a", 1), tuple("a", -1), tuple("b", 2), tuple("b", 25), tuple("c", 100), tuple("b", 21)];
arr.sort!("a[0] > b[0]").group!((a, b) => a[0] == b[0]); //(Tuple!(string, int)("c", 100), 1), (Tuple!(string, int)("b", 25), 3), (Tuple!(string, int)("a", 1), 2)]

Агрегация значений не происходит, и берется только первое значение,Но какой смысл брать только одно первое значение?Можно, конечно, обойти это через

int[][string] res;
arr.each!(s => res[s[0]] ~= [s[1]]);
writeln(res) // ["c":[100], "a":[1, -1], "b":[25, 2, 21]]

, но возможно ли это в одну строку без предопределения res array?

1 Ответ

3 голосов
/ 27 сентября 2019
Tuple!(string, int)[] arr = [tuple("a", 1), tuple("a", -1), tuple("b", 2), tuple("b", 25), tuple("c", 100), tuple("b", 21)];
arr.sort!("a[0] > b[0]").group!((a, b) => a[0] == b[0]); // [Tuple!(string, int)("b", 25):3, Tuple!(string, int)("c", 100):1, Tuple!(string, int)("a", 1):2]

Это не тот результат, который я получаю:

https://run.dlang.io/is/9lVPkv

В результате получается [tuple(tuple("c", 100), 1), tuple(tuple("b", 25), 3), tuple(tuple("a", 1), 2)], что выглядит правильно.

но возможно ли это в одну строку без предопределения res массива?

Я думаю, вы ищете chunkBy:

arr.sort!("a[0] > b[0]").chunkBy!((a, b) => a[0] == b[0]).each!writeln;

Это приводит к :

[Tuple!(string, int)("c", 100)]
[Tuple!(string, int)("b", 25), Tuple!(string, int)("b", 2), Tuple!(string, int)("b", 21)]
[Tuple!(string, int)("a", 1), Tuple!(string, int)("a", -1)]
...