简体   繁体   English

查找数组中所有项目组合的最佳方法是什么?

[英]What is the best way to find all combinations of items in an array?

在 c# 中查找数组中所有项目组合的最佳方法是什么?

"

UPDATED<\/strong>更新<\/strong>

Here are a set of generic functions (require .net 3.5 or higher) for different scenarios.以下是针对不同场景的一组通用函数(需要 .net 3.5 或更高版本)。 The outputs are for a list of {1, 2, 3, 4} and a length of 2.输出是 {1, 2, 3, 4} 和长度为 2 的列表。

Permutations with repetition<\/strong>重复排列<\/strong>

static IEnumerable<IEnumerable<T>> 
    GetPermutationsWithRept<T>(IEnumerable<T> list, int length)
{
    if (length == 1) return list.Select(t => new T[] { t });
    return GetPermutationsWithRept(list, length - 1)
        .SelectMany(t => list, 
            (t1, t2) => t1.Concat(new T[] { t2 }));
}

That's called permutations.这叫做排列组合。

This can give you the permutations of any collection:这可以为您提供任何集合的排列:

public class Permutation {

  public static IEnumerable<T[]> GetPermutations<T>(T[] items) {
    int[] work = new int[items.Length];
    for (int i = 0; i < work.Length; i++) {
      work[i] = i;
    }
    foreach (int[] index in GetIntPermutations(work, 0, work.Length)) {
      T[] result = new T[index.Length];
      for (int i = 0; i < index.Length; i++) result[i] = items[index[i]];
      yield return result;
    }
  }

  public static IEnumerable<int[]> GetIntPermutations(int[] index, int offset, int len) {
    if (len == 1) {
      yield return index;
    } else if (len == 2) {
      yield return index;
      Swap(index, offset, offset + 1);
      yield return index;
      Swap(index, offset, offset + 1);
    } else {
      foreach (int[] result in GetIntPermutations(index, offset + 1, len - 1)) {
        yield return result;
      }
      for (int i = 1; i < len; i++) {
        Swap(index, offset, offset + i);
        foreach (int[] result in GetIntPermutations(index, offset + 1, len - 1)) {
          yield return result;
        }
        Swap(index, offset, offset + i);
      }
    }
  }

  private static void Swap(int[] index, int offset1, int offset2) {
    int temp = index[offset1];
    index[offset1] = index[offset2];
    index[offset2] = temp;
  }

}

Example:例子:

string[] items = { "one", "two", "three" };
foreach (string[] permutation in Permutation.GetPermutations<string>(items)) {
  Console.WriteLine(String.Join(", ", permutation));
}

It is O(n!)它开着!)

static List<List<int>> comb;
static bool[] used;
static void GetCombinationSample()
{
    int[] arr = { 10, 50, 3, 1, 2 };
    used = new bool[arr.Length];
    used.Fill(false);
    comb = new List<List<int>>();
    List<int> c = new List<int>();
    GetComb(arr, 0, c);
    foreach (var item in comb)
    {
        foreach (var x in item)
        {
            Console.Write(x + ",");
        }
        Console.WriteLine("");
    }
}
static void GetComb(int[] arr, int colindex, List<int> c)
{

    if (colindex >= arr.Length)
    {
        comb.Add(new List<int>(c));
        return;
    }
    for (int i = 0; i < arr.Length; i++)
    {
        if (!used[i])
        {
            used[i] = true;
            c.Add(arr[i]);
            GetComb(arr, colindex + 1, c);
            c.RemoveAt(c.Count - 1);
            used[i] = false;
        }
    }
}

Regarding Pengyang answer: Here is my generic function which can return all the combinations from a list of T:关于 Pengyang 的回答:这是我的通用函数,它可以从 T 列表中返回所有组合:

static IEnumerable<IEnumerable<T>>
    GetCombinations<T>(IEnumerable<T> list, int length)
{
    if (length == 1) return list.Select(t => new T[] { t });

    return GetCombinations(list, length - 1)
        .SelectMany(t => list, (t1, t2) => t1.Concat(new T[] { t2 }));
}

There are couples of very easy way to find the combination of string input by user.有几种非常简单的方法可以找到用户输入的字符串组合。

First way by using LINQ使用 LINQ 的第一种方法

<\/blockquote>

private static IEnumerable<string> FindPermutations(string set) { var output = new List<string>(); switch (set.Length) { case 1: output.Add(set); break; default: output.AddRange(from c in set let tail = set.Remove(set.IndexOf(c), 1) from tailPerms in FindPermutations(tail) select c + tailPerms); break; } return output; }<\/code><\/pre>

Use this function like<\/em><\/strong>像这样使用这个功能<\/em><\/strong>

Console.WriteLine("Enter a sting "); var input = Console.ReadLine(); foreach (var stringCombination in FindPermutations(input)) { Console.WriteLine(stringCombination); } Console.ReadLine();<\/code><\/pre> 
         

Other way is to use loop另一种方法是使用循环

<\/blockquote>

\/\/ 1. remove first char \/\/ 2. find permutations of the rest of chars \/\/ 3. Attach the first char to each of those permutations. \/\/ 3.1 for each permutation, move firstChar in all indexes to produce even more permutations. \/\/ 4. Return list of possible permutations. public static string[] FindPermutationsSet(string word) { if (word.Length == 2) { var c = word.ToCharArray(); var s = new string(new char[] { c[1], c[0] }); return new string[] { word, s }; } var result = new List<string>(); var subsetPermutations = (string[])FindPermutationsSet(word.Substring(1)); var firstChar = word[0]; foreach (var temp in subsetPermutations.Select(s => firstChar.ToString() + s).Where(temp => temp != null).Where(temp => temp != null)) { result.Add(temp); var chars = temp.ToCharArray(); for (var i = 0; i < temp.Length - 1; i++) { var t = chars[i]; chars[i] = chars[i + 1]; chars[i + 1] = t; var s2 = new string(chars); result.Add(s2); } } return result.ToArray(); }<\/code><\/pre> 
            

you can use this function like你可以像这样使用这个功能

<\/blockquote>

Console.WriteLine("Enter a sting "); var input = Console.ReadLine(); Console.WriteLine("Here is all the possable combination "); foreach (var stringCombination in FindPermutationsSet(input)) { Console.WriteLine(stringCombination); } Console.ReadLine();<\/code><\/pre>"

Another version of the solution given by Gufa. Gufa给出的解决方案的另一个版本。 Below the complete source code of the class:下面是类的完整源代码:

using System.Collections.Generic;

namespace ConsoleApplication1
{
    public class Permutation
    {

        public IEnumerable<T[]> GetPermutations<T>(T[] items)
        {
            var work = new int[items.Length];
            for (var i = 0; i < work.Length; i++)
            {
                work[i] = i;
            }
            foreach (var index in GetIntPermutations(work, 0, work.Length))
            {
                var result = new T[index.Length];
                for (var i = 0; i < index.Length; i++) result[i] = items[index[i]];
                yield return result;
            }
        }

        public IEnumerable<int[]> GetIntPermutations(int[] index, int offset, int len)
        {
            switch (len)
            {
                case 1:
                    yield return index;
                    break;
                case 2:
                    yield return index;
                    Swap(index, offset, offset + 1);
                    yield return index;
                    Swap(index, offset, offset + 1);
                    break;
                default:
                    foreach (var result in GetIntPermutations(index, offset + 1, len - 1))
                    {
                        yield return result;
                    }
                    for (var i = 1; i < len; i++)
                    {
                        Swap(index, offset, offset + i);
                        foreach (var result in GetIntPermutations(index, offset + 1, len - 1))
                        {
                            yield return result;
                        }
                        Swap(index, offset, offset + i);
                    }
                    break;
            }
        }

        private static void Swap(IList<int> index, int offset1, int offset2)
        {
            var temp = index[offset1];
            index[offset1] = index[offset2];
            index[offset2] = temp;
        }

    }
}

This actually worked as it should for combinations.But is does not allow to chose combinations of n in k ...这实际上适用于组合。但是不允许在 k 中选择 n 的组合...

For detailed answer see: Donald Knuth, The Art of computer programming (aka TAOCP).有关详细答案,请参阅:Donald Knuth,计算机编程艺术(又名 TAOCP)。 Volume 4A, Enumeration and Backtracking, chapter 7.2.第 4A 卷,枚举和回溯,第 7.2 章。 Generating all possibilities.产生所有的可能性。 http://www-cs-faculty.stanford.edu/~uno/taocp.html http://www-cs-faculty.stanford.edu/~uno/taocp.html

How about some recursion?一些递归怎么样?

internal HashSet<string> GetAllPermutations(IEnumerable<int> numbers)
{
  HashSet<string> results = new HashSet<string>();

  if (numbers.Count() > 0)
    results.Add(string.Join(",", new SortedSet<int>(numbers)));

  for (int i = 0; i <= numbers.Count() - 1; i++)
  {
    List<int> newNumbers = new List<int>(numbers);
    newNumbers.RemoveAt(i);
    results.UnionWith(GetAllPermutations(newNumbers));
  }

  return results;
}

I created a method to get the unique combination of all the integer elements in an array as shown below.我创建了一种方法来获取数组中所有整数元素的唯一组合,如下所示。 I've used Tuple<\/code> to represent a pair or combination of numbers:我用Tuple<\/code>来表示一对或数字组合:

private static void CombinationsOfItemsInAnArray()    
{
        int[] arr = { 10, 50, 3, 1, 2 }; //unique elements

        var numberSet = new HashSet<int>();
        var combinationList = new List<Tuple<int, int>>();
        foreach (var number in arr)
        {
            if (!numberSet.Contains(number))
            {
                //create all tuple combinations for the current number against all the existing number in the number set
                foreach (var item in numberSet)
                    combinationList.Add(new Tuple<int, int>(number, item));

                numberSet.Add(number);
            }
        }

        foreach (var item in combinationList)
        {
            Console.WriteLine("{{{0}}} - {{{1}}}",item.Item1,item.Item2);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM