Search code examples
functional-programmingd

Why is .array necessary after .group to use .sort?


Having the following piece of code:

import std.algorithm : filter, canFind, map, splitter, group, sort;
import std.stdio : File, writefln;
import std.range : array;

void main(string[] args)
{
    string filename = "/var/log/dpkg.log";

    string term = args[1];
    auto results = File(filename, "r")
                    .byLine
                    .filter!(a => canFind(a, term))
                    .map!(a => splitter(a, ":").front)
                    .group
                    .array  // why is this crucial ?
                    .sort!((a,b) => a[1] > b[1]);

    foreach (line; results)
        writefln("%s => %s times", line[0], line[1]);
}

I have discovered that I desperately need the .array after .group. Can anyone tell me why is that?

As soon as I get rid of it I get the following compiler error:

main.d(16): Error: template std.algorithm.sorting.sort cannot deduce function from argument types !((a, b) => a[1] > b[1])(Group!("a == b", MapResult!(__lambda3, FilterResult!(__lambda2, ByLine!(char, char))))), candidates are:
/usr/include/dmd/phobos/std/algorithm/sorting.d(1830):        std.algorithm.sorting.sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) if ((ss == SwapStrategy.unstable && (hasSwappableElements!Range || hasAssignableElements!Range) || ss != SwapStrategy.unstable && hasAssignableElements!Range) && isRandomAccessRange!Range && hasSlicing!Range && hasLength!Range)

Solution

  • The result of group is a lazily-evaluated sequence, but sort requires its full input to be fully in-memory, e.g. an array. The array function takes the lazy sequence produced by group and stores it into an array which sort is able to act upon.