给定一个序列序列的类型,如何将其转换为单个扁平的序列类型?请考虑以下Ceylon代码:
Integer[] range(Integer max) {
return [ for (idx in 1..max) idx ];
}
Integer[] prod(Integer max, Integer occurrences) {
Integer[][] nestedSequence = [for (occurrence in 1..occurrences) range(max)];
return // ??? something to produce a flattened sequence
}
assert (prod(2, 2) == [1, 2, 1, 2]);
我第一次尝试使用Ceylon,并在教程和API文档中摸索着。 unzip method看起来有点接近我的需要,但不完全正确。
答案 0 :(得分:5)
可变函数concatenate()
连接迭代,产生一个序列:
Integer[] prod(Integer max, Integer occurrences) {
Integer[][] nestedSequence = [ for (occurrence in 1..occurrences) range(max) ];
return concatenate(*nestedSequence);
}
这可以像下面那样冗长地重写:
Integer[] prod(Integer max, Integer occurrences)
=> concatenate(for (occurrence in 1..occurrences) range(max));
但是我不喜欢这个实现,因为它做了很多急切的序列实例化。我很多更喜欢这个实现,它只进行一次序列实例化:
Integer[] prod4(Integer max, Integer occurrences)
=> [ for (occurrence in 1..occurrences) for (x in range(max)) x ];
仅供参考,在Ceylon 1.1中,添加了expand()
函数,该函数比concatenate()
更加懒散。
答案 1 :(得分:1)
你的range
函数在这里没用,因为它不必要地在一个范围内创建一个序列。您只需要从1
迭代到max
,您就可以直接使用1..max
创建的范围来执行此操作。因此,将range(max)
替换为1..max
,您可以像这样定义prod
:
Integer[] prod(Integer max, Integer occurrences)
=> (1..max).repeat(occurrences);
要回答您的问题,在Gavin's answer中没有提及concatenate
和expand
的情况下,您可以使用nestedSequence
从Iterable.fold()
生成扁平化序列像这样:
nestedSequence.fold({}, ({Integer*} f, Integer[] r) => f.chain(r)).sequence;
同样地,
Element[] flattened<Element>(Element[][] nestedSequence) {
variable {Element*} flattened = {}; // same as f above
for (Element[] range in nestedSequence) { // range is same as r above
flattened = flattened.chain(range);
}
return flattened.sequence;
}
但我更喜欢Gavin的最后一次实施,使用了解。与fold
相比,我认为更像是惯用的锡兰。