如何测试集合是否包含其他集合的所有元素

时间:2018-01-25 11:26:17

标签: ceylon

在Ceylon中使用Set可以直接确定一个集合是否是另一个集合的超集。它只是first.superset(second)。使用multiset(或包)语义对IterableListSequential执行等效操作的最佳方法是什么?例如下面的伪代码:

{'a', 'b', 'b', 'c'}.containsAll({'b', 'a'}) // Should be true
{'a', 'b', 'b', 'c'}.containsAll({'a', 'a'}) // Should be false

3 个答案:

答案 0 :(得分:4)

Category.containsEvery,由Iterable继承。它检查参数的每个元素是否包含在接收器中,因此bigger.containsEvery(smaller)等同于:

smaller.every(bigger.contains)

(注意它是交换的。)这里括号中的表达式是方法引用,我们也可以用lambda编写这个扩展:

smaller.every(o => bigger.contains(o))

所以在你的例子中:

print({'a', 'b', 'b'}.containsEvery({'b', 'a'})); // Should be true
print({'a', 'b', 'b'}.containsEvery({'a', 'a'})); // Should be false

......实际上,这些都是真的。为什么你认为后者是假的?

您是否考虑过多重语义(即"超集&#34中的出现次数;迭代次数至少需要与较小的次数一样多)?或者你想要一个子列表?或者你只是想知道第二个迭代是否在第一个(startwith)的开头?

我不知道Ceylon的任何 multiset 实现(我发现了multimap)。如果你在JVM上运行,你可以使用任何Java,比如来自Guava(虽然它也没有"包含所有带有倍数"函数,据我所知)。 对于小型迭代,您可以使用.frequencies()然后比较数字:

Boolean isSuperMultiset<Element>({Element*} bigger,
                                 {Element*} smaller) =>
     let (bigFreq = bigger.frequencies())
        every({ for(key->count in smaller.frequencies())
                count <= (bigFreq[key] else 0) })

对于子列表语义,SearchableList接口具有includes方法,该方法检查另一个列表是否是子列表。 (它不是由很多类实现的,但是,你需要将你的第一个iterable转换为一个Array,假设它不是一个String / StringBuilder。)

对于startsWith语义,您可以将两者都转换为列表,然后使用List.startsWith。应该有一种更有效的方法(你可以并行浏览两个迭代器)。

corresponding,但它只是在较短的一个结束后停止(即它回答问题&#34;这两个迭代中的任何一个是从另一个开始的#34;,而不知道哪一个是更长的一个)。对于ceylon.language中的一堆其他对相关函数也是如此。

如果你知道两个Iterables的长度(或者确信.size很快),那应该可以解决问题:

Boolean startsWith<Element>({Element*}longer, {Element*}shorter) =>
     shorter.size <= longer.size &&
     corresponding(longer, shorter);

答案 1 :(得分:1)

如果您有两个Sequential,那么您可以从左侧序列中逐个删除每个右手角色,直到您将其全部删除或无法删除其中一个。

Boolean containsAll<Element>([Element*] collection, [Element*] other)
        given Element satisfies Object {
    variable value remaining = collection;

    for (element1 in other) {
        value position = remaining.locate((element2) => element1 == element2);
        if (exists position) {
            remaining = remaining.initial(position.key).append(remaining.spanFrom(position.key + 1));
        } else {
            // Element was not found in remaining; terminate early
            return false;
        }
    }

    // All elements were found
    return true;
}

print(containsAll(['a', 'b', 'b', 'c'], ['a', 'b']));
print(containsAll(['a', 'b', 'b', 'c'], ['a', 'a']));

附加仅存在于Sequential上,因此它不仅适用于ListIterable

答案 2 :(得分:0)

containsEvery函数应该执行您想要的操作(try it!)。或者,您也可以使用set函数(try it!)将两个流转换为集合,或使用everycontainstry it!)。