3

有没有办法“洗牌”一个Iterable(或Sequence),以便随后随机排序元素,类似于Java的Collections.shuffle()?我查看了、 和的 API 文档Iterable,但没有发现任何相关内容。(旁注:名称混淆)CollectionSequenceceylon.language::shuffle

我想我可以自己实施洗牌,但我正忙着偷懒:-)

4

3 回答 3

1

我也去找这个了,没找到。这是一个实现:

import ceylon.collection {ArrayList}
import ceylon.math.float {random}

"Don't interleave multiple iterators!"
Iterable<Element, Absent> shuffle<Element, Absent>(Iterable<Element, Absent> elements)
        given Absent satisfies Null => object satisfies Iterable<Element, Absent> {
    value list = ArrayList{elements = elements;};
    iterator() => object satisfies Iterator<Element> {
        variable value index = list.size;
        shared actual Element|Finished next() {
            value randomIndex = (random() * index--).integer;
            if (exists element = list[index]) {
                assert (exists randomElement = list[randomIndex]);
                list.set(index, randomElement);
                list.set(randomIndex, element);
                return randomElement;
            }
            return finished;
        }
    };
};
于 2013-12-10T06:25:26.580 回答
1

SDK 现在包含ceylon.random具有以下randomize功能的模块:

List<Elements> randomize<Elements>({Elements*} elements)

于 2016-03-29T17:08:22.457 回答
0

我最终实现了我自己的,基于最后一个“由内而外”算法here

[Element*] shuffle<Element>({Element*} input) {
    value newList = LinkedList<Element>();
    for(el in input){
        value j = math.randomInteger {lowerBound=0; upperBound=newList.size; inclusiveUpperBound=true;};
        if(j == newList.size){
            newList.add(el);
        } else {
            value elementToMove = newList[j];
            assert(exists elementToMove);
            newList.add(elementToMove);
            newList.set(j, el);
        }
    }
    return newList.sequence;
}

还没有验证正确性。我也实现了 math.randomInteger ,你可能会猜到它的实现。

于 2013-12-10T06:37:27.177 回答