加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

.net – 生成IEnumerable(Of T)的元素的所有唯一组合

发布时间:2020-12-17 07:15:42 所属栏目:百科 来源:网络整理
导读:这个问题与 this SO post几乎相同,只是我在寻找VB.NET(.NET 4)解决方案.我已经足够长时间旋转我的车轮,试图想出一个解决这个“动力装置”问题的通用解决方案. 鉴于: Dim choices As IEnumerable(Of String) = {"Coffee","Tea","Milk","Cookies"}Dim choiceS
这个问题与 this SO post几乎相同,只是我在寻找VB.NET(.NET 4)解决方案.我已经足够长时间旋转我的车轮,试图想出一个解决这个“动力装置”问题的通用解决方案.

鉴于:

Dim choices As IEnumerable(Of String) = {"Coffee","Tea","Milk","Cookies"}
Dim choiceSets = choices.CombineAll()

我正在寻找choiceSets是一个IEnumerable(IEnumerable(Of T)),所以我可以这样做:

For each choiceSet in choiceSets
    Console.WriteLine(String.Join(",",choiceSet))
Next

并获得如下结果:

Coffee
Tea
Milk
Cookies
Coffee,Tea
Coffee,Milk
Coffee,Cookies
Tea,Milk
Tea,Cookies
Milk,Cookies
Coffee,Tea,Milk,Cookies

正如您所看到的,这是来自源IEnumerable(Of T)的每个非重复组合(其中可能包含1到多个项目 – 此示例仅有4个),它根据源中项目的顺序进行操作IEnumerable(Of T),并且列表中的每个项目都是> =内部IEnumerable(Of T)中的项目数量的前一项目.

对于它的价值,这不是功课;虽然它确实感觉像它.

编辑:更新了示例,因此看起来结果不按字母顺序排序,强调使用源IEnumerable(Of T)的现有顺序,并添加第4个选项以阐明每个集合中的排序要求.

解决方法

这是一个纯粹的Linq解决方案,灵感来自Eric Lippert关于计算笛卡尔积的 blog post.我稍微修改了CartesianProduct方法,以便返回组合:

public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<IEnumerable<T>> sequences)
{
    IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
    return sequences.Aggregate(
        emptyProduct,(accumulator,sequence) => 
        from accseq in accumulator 
        // Exclude items that were already picked
        from item in sequence.Except(accseq)
        // Enforce ascending order to avoid same sequence in different order
        where !accseq.Any() || Comparer<T>.Default.Compare(item,accseq.Last()) > 0
        select accseq.Concat(new[] {item})).ToArray();
}

基于此扩展方法,您可以生成所需的结果,如下所示:

IEnumerable<string> items = new[] {"Coffee","Milk"};
IEnumerable<IEnumerable<string>> result =
    Enumerable.Range(1,items.Count())
        .Aggregate(
            Enumerable.Empty<IEnumerable<string>>(),(acc,i) =>
                acc.Concat(Enumerable.Repeat(items,i).Combinations()));

(它连接1,2 … N项的所有组合)

请注意,它可能不是一个非常有效的解决方案,但我认为这是一个有趣的使用Linq …

编辑:这是一个新版本的组合方法,维护原始顺序:

public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<IEnumerable<T>> sequences)
{
    var indexedSequences = sequences.Select(seq => seq.Select((item,idx) => new IndexedItem<T>(item,idx)));
    IEnumerable<IEnumerable<IndexedItem<T>>> emptyProduct = new[] { Enumerable.Empty<IndexedItem<T>>() };
    var indexedResult =
        indexedSequences.Aggregate(
            emptyProduct,sequence) => 
            from accseq in accumulator 
            // Exclude items that were already picked
            from item in sequence.Except(accseq)
            // Enforce ascending order of indexes to avoid same sequence in different order
            where !accseq.Any() || item.Index > accseq.Last().Index
            select accseq.Concat(new[] {item})).ToArray();
    return indexedResult.Select(seq => seq.Select(i => i.Item));
}

class IndexedItem<T>
{
    public IndexedItem(T item,int index)
    {
        this.Item = item;
        this.Index = index;
    }

    public T Item { get; private set; }
    public int Index { get; set; }
}

可能比以前的版本效率更低,但它完成了工作……

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读