从列表中投射字符串

时间:2013-10-15 16:39:47

标签: c# linq

我有一个字符串列表,每个字符串都是可变长度的。我想从列表中投出一个子集,该子集具有从长度等于5的原始列表连接的字符串。我正在使用聚合函数,但它没有给出我想要的结果。什么是适合此投影的LINQ查询?你能帮忙吗?

代码:

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<string> items = new List<string> {"abc", "ab", "abcd", "abcde", "abcdef", "a", "ab", "cde"};

        //All combinations of concatenations equal to length 5.
        //Only need to process an item once and need to concatenate 2 items and no more

        var filteredList = items.Where(x => x.Length < 5)
                                .Aggregate(Execute).ToList();

        foreach (var f in filteredList)
        {
            //Should out put : abc+ab = abcab
            //Should out put : abcde
            //Should out put : abcd+a = abcda
            //Should out put : ab+cde = abcde
            Console.WriteLine(f);
        }
    }

    private static string Execute(string a, string b)
    {
        if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b))
            return null;

        if ((a.Length + b.Length) == 5)
            return a + b;

        return null;
    }
}

几点:

  • 处理完一件商品后,我不需要再次考虑该商品

  • 以上是真的,直到我在列表中再次找到相同的项目,一旦我找到它,我应该尝试将它与另一个在先前串联中未使用的项目连接。

  • 不需要它是LINQ,我只是在寻找解决方案。

  • 输出不能包含两个以上的字符串? (a + bc + de)不是必需的。

  • 项目不需要与自身连接。

  • 我已将输出作为问题的一部分提及。

注意:使用.NET 3.5(但如果可能,也希望在.NET 4.0中看到快捷方式)

6 个答案:

答案 0 :(得分:1)

        List<string> items = new List<string> { "abc", "ab", "abcd", "abcde", "abcdef", "a", "ab", "cde" };
        var result = items
                        .SelectMany((x, i) => items.Skip(i + 1).Concat(new[] {string.Empty}), (s1, s2) => s1 + s2)
                        .Where(s => s.Length == 5);

答案 1 :(得分:1)

如果你问我,我说:“不要偷懒。”

    private static List<string> ValidCombinationsFind(List<string> iSource)
    {
        List<string> lstResult = new List<string>();

        //Use and explicit mask to remember indexes in iSource which were used.
        bool[] ablnUsageMask = new bool[iSource.Count];

        int intCurrentIndex = 0;

        //Examine the source list one by one.
        while (intCurrentIndex < iSource.Count - 1)
        {
            //If the next item is not already used then go on.
            if (!ablnUsageMask[intCurrentIndex])
            {
                string strCurrentItem = iSource[intCurrentIndex];

                //If the item is ok then check every remaining item for a match.
                if (!string.IsNullOrEmpty(strCurrentItem))
                {
                    //Check if an item fits on its own.
                    if (strCurrentItem.Length == 5)
                    {
                        ablnUsageMask[intCurrentIndex] = true;
                        lstResult.Add(strCurrentItem);
                    }
                    else
                    {
                        for (int intNextItemIndex = intCurrentIndex + 1; intNextItemIndex < iSource.Count; intNextItemIndex++)
                        {
                            //If the next item is not already used then go on.
                            if (!ablnUsageMask[intNextItemIndex])
                            {
                                string strNextItem = iSource[intNextItemIndex];

                                if (!string.IsNullOrEmpty(strNextItem))
                                {
                                    if ((strCurrentItem.Length + strNextItem.Length) == 5)
                                    {
                                        ablnUsageMask[intCurrentIndex] = true;
                                        ablnUsageMask[intNextItemIndex] = true;
                                        lstResult.Add(strCurrentItem + strNextItem);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            intCurrentIndex++;
        }

        return lstResult;
    }

答案 2 :(得分:0)

void Main()
{
    var items = new List<string> {"abc", "ab", "abcd", "abcde", "abcdef", "a", "ab", "cde"};
    bool[] flag=new bool[items.Count()];
    var output=items.SelectMany((x,i)=>items.Select((y,j)=>concat(flag,items,i,j)))
                    .Where(x=>x!="");
}

public string concat(bool[] flag,List<string> items,int i,int j)
{
if(flag[i]==false && flag[j]==false && (items[i].Length==5||(items[i]+items[j]).Length==5))
{
      flag[i]=true;
      flag[j]=true;

      if(i==j)return items[i];
      else return items[i]+","+items[j];
}
else return "";
}

输出:

abc,ab 
abcd,a 
abcde 
ab,cde 

答案 3 :(得分:0)

我相信这可以做你想要的:

  var filteredList = items.Where(x => x.Length < 5)
    .SelectMany(x => items, (y, z) => { return Execute(y, z); })
    .Where(x => x != null).Distinct().ToList();

答案 4 :(得分:0)

所以这里的想法是配对对象,使这两个对象具有完全正确的大小。我们在这里可以做的是按照它们的大小对所有字符串进行分组。我们知道所有尺寸为1和4的物品都需要配对,2和3尺寸的物品需要配对,而5号尺寸的物品则需要配对。

因此,我们可以迭代可能的大小,抓住具有该大小的组和具有大小的组来创建所需的项目,然后压缩这两个集合。 Zip将从第一组中获取第一项,将其与第二项中的第一项匹配,然后对每个索引进行匹配。这意味着每个字符串都不会重复。然后我们可以将最合适尺寸的物品添加到最后。

private static IEnumerable<string> MakeDesiredSize(
    List<string> items, int desiredSide)
{
    var lookup = items.Where(item => item.Length <= desiredSide)
        .ToLookup(item => item.Length);
    return Enumerable.Range(1, desiredSide / 2)
            .SelectMany(i => lookup[i].Zip(lookup[desiredSide - i]
                , (a, b) => a + b))
            .Concat(lookup[desiredSide]);
}

由于您使用的是3.5,因此这是Zip的实现:

public static IEnumerable<TResult> Zip<TSource, TResult>(
    this IEnumerable<TSource> first,
    IEnumerable<TSource> second,
    Func<TSource, TSource, TResult> resultSelector)
{
    using (var itOne = first.GetEnumerator())
    using (var itSecond = second.GetEnumerator())
        while (itOne.MoveNext() & itSecond.MoveNext())
            yield return resultSelector(itOne.Current, itSecond.Current);
}

答案 5 :(得分:0)

使用双for循环同时跟踪哪些索引匹配应该这样做:

IEnumerable<string> items = new List<string> { "abc", "ab", "abcd", "abcde", "abcdef", "a", "ab", "cde" };
var filteredList = GimmeFives(items).ToList();

private IEnumerable<string> GimmeFives(IEnumerable<string> items)
{
    //"Once an item is processed, I dont need to consider that item again for a combination"
    var indexesProcessed = new List<int>();

    for (int i = 0; i < items.Count(); i++)
    {
        if (indexesProcessed.Contains(i)) { continue; }

        var first = items.ElementAt(i);
        if (first.Length == 5)
        {
            yield return first;
        }
        else
        {
            //Start the second loop after index "i", to avoid including previously processed items:
            for (int j = i+1; j < items.Count(); j++)
            {
                if (indexesProcessed.Contains(j)) { continue; }

                var second = items.ElementAt(j);

                if ((first.Length + second.Length) == 5)
                {
                    //Remove the middle "+" sign in production code...
                    yield return (first + "+" + second);

                    indexesProcessed.Add(i);
                    indexesProcessed.Add(j);

                    //"Once an item is processed, I dont need to consider that item again for a combination"
                    //"first" has gotten its match, so we don't need to search for another "second":
                    break;
                }
            }
        }

    }
}

输出:

abc+ab
abcd+a
abcde
ab+cde