使用LINQ

时间:2016-03-22 21:40:48

标签: c# .net vb.net linq permutation

这个问题包含VB.NET代码,但我可以接受C#中解释的解决方案。

SCENARIO

过去,在StackOverflow帮助用户的帮助下,我构建了这个函数,用于排列字符:

<DebuggerStepThrough>
Public Shared Function PermuteCharacters(ByVal charSet As IEnumerable(Of Char),
                                         ByVal length As Integer,
                                         ByVal allowRepetition As Boolean) As IEnumerable(Of String)

    If (charSet.Count <> charSet.Distinct.Count) Then
        Throw New ArgumentException("Char-set contains duplicated characters.", "charSet")
        Return Nothing
    End If

    If (length = 1) Then
        Return charSet.Select(Function(c As Char)
                                  Return New String(New Char() {c})
                              End Function)
    End If

    If (allowRepetition) Then
        Return PermuteCharacters(charSet:=charSet, length:=length - 1, allowRepetition:=True).
               SelectMany(Function(str As String)
                              Return charSet
                          End Function,
                          Function(str As String, c As Char)
                              Return str & c
                          End Function)

    Else
        Return PermuteCharacters(charSet:=charSet, length:=length - 1, allowRepetition:=False).
           SelectMany(Function(x As String) charSet,
                      Function(str As String, c As Char)
                          If Not str.Contains(c) Then
                              Return str & c
                          Else
                              Return Nothing
                          End If
                      End Function).
        Where(Function(value As String) value IsNot Nothing)

    End If

End Function

问题

现在,在C#或Vb.Net中,我想要排列集合元素之间的所有可能组合(只有数字类型或字符串的集合)。

这是我到目前为止所做的,它是不完整的,并没有给我预期的结果:

Public Shared Function PermuteItems(ByVal items As IEnumerable(Of String)) As IEnumerable(Of IEnumerable(Of String))

    Return items.SelectMany(
        Function(x As String) As IEnumerable(Of String)
            Return items
        End Function,
        Function(str1 As String, str2 As String) As IEnumerable(Of String)
            Return {str1}.Concat({str2})
        End Function)

End Function

Public Shared Function PermuteItems(ByVal items As IEnumerable(Of Integer)) As IEnumerable(Of IEnumerable(Of String))

    Return PermuteItems((From item As Integer In items Select Convert.ToString(item)))

End Function

我需要帮助来修复我得到的结果值,我只收集了两个元素的集合。

对我来说保留 LINQ-to-Object 方法非常重要。

C#online(和未经测试的)翻译:

public static IEnumerable<IEnumerable<string>> PermuteItems(IEnumerable<string> items) {
    return items.SelectMany((string x) => { return items; }, (string str1, string str2) => { return { str1 }.Concat({ str2 }); });
}

public static IEnumerable<IEnumerable<string>> PermuteItems(IEnumerable<int> items) {
    return PermuteItems((from item in itemsConvert.ToString(item)));
}

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================

的期望

如果我将数组传递给包含这些元素的函数: {10,2,30} ,那么它应该返回一个包含这些集合的IEnumerable(Of IEnumerable(Of Integer))

  • 第1项:{2,10,30}
  • 第2项:{2,30,10}
  • 第3项:{10,2,30}
  • 第4项:{10,30,2}
  • 第5项:{30,10,2}
  • 第6项:{30,2,10}

如果我将数组传递给包含这些元素的函数: {&#34; abc&#34;,&#34;&#34;,&#34; abc&#34;} 然后它应该返回一个包含这些集合的IEnumerable(Of IEnumerable(Of String))

  • 第1项:{&#34;&#34;,&#34; abc&#34;,&#34; abc&#34;}
  • 第2项:{&#34; abc&#34;,&#34;&#34;,&#34; abc&#34;}
  • 第3项:{&#34; abc&#34;,&#34; abc&#34;,&#34;&#34;}

元素可以是等号,集合不是。

顺序很重要,但我明白这是一个不同的问题,我认为我可以通过LINQ分组或排序来解决这个问题。

3 个答案:

答案 0 :(得分:2)

这对我有用:

public IEnumerable<IEnumerable<T>> Permutate<T>(IEnumerable<T> source)
{
    var xs = source.ToArray();
    return
        xs.Length == 1
            ? new [] { xs }
            : (
                from n in Enumerable.Range(0, xs.Length)
                let cs = xs.Skip(n).Take(1)
                let dss = Permutate<T>(xs.Take(n).Concat(xs.Skip(n + 1)))
                from ds in dss
                select cs.Concat(ds)
            ).Distinct(new EnumerableEqualityComparer<T>());
}

private class EnumerableEqualityComparer<T> : IEqualityComparer<IEnumerable<T>>
{
    public bool Equals(IEnumerable<T> a, IEnumerable<T> b)
    {
        return a.SequenceEqual(b);
    }

    public int GetHashCode(IEnumerable<T> t)
    {
        return t.Take(1).Aggregate(0, (a, x) => a ^ x.GetHashCode());
    }
}

var source = new[] { 10, 2, 30 };我得到:

{10, 2, 30} 
{10, 30, 2} 
{2, 10, 30} 
{2, 30, 10} 
{30, 10, 2} 
{30, 2, 10} 

我得到var source = new[] { "abc", "", "abc" };

{"abc", "", "abc"} 
{"abc", "abc", ""} 
{"", "abc", "abc"} 

Vb.Net等价物:

Public Function Permutate(Of T)(source As IEnumerable(Of T)) As IEnumerable(Of IEnumerable(Of T))

    Dim xs As T() = source.ToArray()

    Return If(xs.Length = 1,
              {xs},
              (From n In Enumerable.Range(0, xs.Length)
               Let cs = xs.Skip(n).Take(1)
               Let dss = Permutate(Of T)(xs.Take(n).Concat(xs.Skip(n + 1)))
               From ds In dss Select cs.Concat(ds))
              ).Distinct(New EnumerableEqualityComparer(Of T)())

End Function

Public Class EnumerableEqualityComparer(Of T) : Implements IEqualityComparer(Of IEnumerable(Of T))

    Public Shadows Function Equals(a As IEnumerable(Of T), b As IEnumerable(Of T)) As Boolean _
    Implements IEqualityComparer(Of IEnumerable(Of T)).Equals
        Return a.SequenceEqual(b)
    End Function

    Public Shadows Function GetHashCode(t As IEnumerable(Of T)) As Integer Implements _
    IEqualityComparer(Of IEnumerable(Of T)).GetHashCode
        Return t.Take(1).Aggregate(0, Function(a, x) a Xor x.GetHashCode())
    End Function

End Class

答案 1 :(得分:2)

查看Combinatorics - 一个nuget包(和source code)来计算排列和组合。

答案 2 :(得分:0)

不确定性能。但紧凑

var permutation = list.SelectMany((item,i) => list.Skip(i + 1).Select((another) => (item, another)));