【问题标题】:C# All Unique Combinations of List<string> [duplicate]C# List<string> 的所有唯一组合 [重复]
【发布时间】:2018-10-17 21:08:02
【问题描述】:

这个问题已经被问过很多次了,但是我看到的每一个 SO 帖子都需要一个特定的值长度,而我只想知道每个独特的组合,无论长度如何。

下面的代码仅提供了一个列表,其中恰好有 3 个组合条目(并且它们不是唯一的)。

List<string> list = new List<string> { "003_PS", "003_DH", "003_HEAT" };
var perms = list.GetPermutations();

public static class Extensions 
{
    public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            var itemAsEnumerable = Enumerable.Repeat(item, 1);
            var subSet = items.Except(itemAsEnumerable);
            if (!subSet.Any())
            {
                yield return itemAsEnumerable;
            }
            else
            {
                foreach (var sub in items.Except(itemAsEnumerable).GetPermutations())
                {
                    yield return itemAsEnumerable.Union(sub);
                }
            }
        }
    }
}

/*
  OUTPUT:
      003_PS,   003_DH,   003_HEAT
      003_PS,   003_HEAT, 003_DH
      003_DH,   003_PS,   003_HEAT
      003_DH,   003_HEAT, 003_PS
      003_HEAT, 003_PS,   003_DH
      003_HEAT, 003_DH,   003_PS
*/

我要找的是这个:

/*
OUTPUT:
    003_PS, 003_DH, 003_HEAT
    003_PS, 003_DH
    003_PS, 003_HEAT
    003_PS

    003_DH, 003_HEAT
    003_DH

    003_HEAT
 */

大小不限3件,每个条目都是唯一的。

我需要在此功能中进行哪些更改?我愿意接受 LINQ 解决方案

感谢任何帮助。谢谢!

编辑:上面的列表输出不准确

**编辑#2: 这是我正在寻找的 Javascript 版本。但我不知道 C# 等效语法是什么:

function getUniqueList(arr){
    if (arr.length === 1) return [arr];
    else {
        subarr = getUniqueList(arr.slice(1));
        return subarr.concat(subarr.map(e => e.concat(arr[0])), [[arr[0]]]);
    }
}

.

【问题讨论】:

标签: c# combinations permutation


【解决方案1】:

好的,你有 n 个项目,并且你想要这些项目的 2n 个组合。

仅供参考,当您在片场进行时,这被称为“动力组”;由于序列可以包含重复项而集合不能,因此您想要的不是 完全 幂集,但它已经足够接近了。如果您的序列包含重复项,我提供的代码在某种意义上是错误的,因为我们会说 {10, 10} 的结果将是 {}, {10}, {10}, {10, 10} 但如果您不喜欢这样,那么在开始之前删除重复项,然后您将计算幂集。

计算所有组合的序列很简单。我们的推理如下:

  • 如果有零个项目,那么只有一个组合:有零个项目的组合。
  • 如果有 n > 0 个项目,则组合是 第一个元素的所有组合,以及 没有 第一个元素的所有组合。

让我们写代码:

using System;
using System.Collections.Generic;
using System.Linq;

static class Extensions
{
    public static IEnumerable<T> Prepend<T>(
        this IEnumerable<T> items,
        T first)
    {
        yield return first;
        foreach(T item in items)
            yield return item;
    }
    public static IEnumerable<IEnumerable<T>> Combinations<T>(
        this IEnumerable<T> items)
    {
        if (!items.Any())
            yield return items;
        else
        {
          var head = items.First();
          var tail = items.Skip(1);
          foreach(var sequence in tail.Combinations()) 
          {
            yield return sequence; // Without first
            yield return sequence.Prepend(head);
          }
       }
    }
}

public class Program
{
    public static void Main()
    {
        var items = new [] { 10, 20, 30 };
        foreach(var sequence in items.Combinations())
            Console.WriteLine($"({string.Join(",", sequence)})");
    }
}

我们得到输出

()
(10)
(20)
(10,20)
(30)
(10,30)
(20,30)
(10,20,30)

请注意,如果原始序列很长,则此代码效率不高

练习 1:你明白为什么了吗?

练习 2:对于长序列,您能否让这段代码在时间和空间上都高效? (提示:如果您可以使 headtailprepend 操作更节省内存,那将大有帮助。)

练习 3:在 JavaScript 中给出相同的算法;你能把JS算法的各个部分和C#版本做个类比吗?

当然,我们假设原始序列中的项目数很短。如果它甚至是 100 个,那么您将等待 很长 时间来枚举所有这些数万亿个组合。

如果您想获得所有具有特定数量元素的组合,请参阅我关于算法的系列文章:https://ericlippert.com/2014/10/13/producing-combinations-part-one/

【讨论】:

  • 我真的很喜欢你的回答和博客。感谢您分享您的知识!
猜你喜欢
  • 1970-01-01
  • 2018-11-10
  • 1970-01-01
  • 1970-01-01
  • 2017-03-29
  • 2023-03-18
  • 1970-01-01
  • 2021-04-04
  • 2018-11-11
相关资源
最近更新 更多