有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
...实际上,它们都返回 true。为什么你认为后一个是假的?
您是否考虑过多集语义(即“超集”迭代中的出现次数至少需要与较小的一样多)?或者你想要一个子列表?还是您只想知道第二个可迭代对象是否在第一个可迭代对象的开头(startswith)?
我不知道 Ceylon 的任何multiset实现(不过我找到了一个multimap)。如果您在 JVM 上运行,则可以使用任何 Java,例如来自 Guava 的 Java(尽管据我所知,它也没有“包含所有多个”功能)。对于小型迭代,您可以使用.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
方法,该方法检查另一个列表是否是子列表。(虽然很多类都没有实现它,但您需要将第一个可迭代对象转换为数组,假设它不是 String/StringBuilder。)
对于 startsWith 语义,您可以将两者都转换为列表并使用 then List.startsWith
。应该有一种更有效的方法来做到这一点(你可以并行通过两个迭代器)。
有corresponding
,但它只是在较短的结束后停止(即它回答了“这两个迭代中的任何一个是否从另一个开始”的问题,而不告诉哪个是较长的)。ceylon.language 中的一堆其他对相关函数也是如此。
如果您知道两个 Iterables 的长度(或者确信它.size
很快),那应该可以解决问题:
Boolean startsWith<Element>({Element*}longer, {Element*}shorter) =>
shorter.size <= longer.size &&
corresponding(longer, shorter);