用linq代码替换循环

时间:2018-01-21 17:17:14

标签: c# linq

我目前的代码是这样的:

    var results = new List<Results>();

    var items = new List<string>
    {
        "B,0",
        "A,1",
        "B,2",
        "A,3",
        "A,4",
        "B,5",
        "A,6",
        "A,7",
        "B,8"
    };

    int size = 2;
    int temp;
    var tempResults = new List<int>();

    var keys = items.Select(t => t.Split(',')[0]).Distinct().ToList();
    //var values = items.Select(t => t.Split(',')[1]).ToList();

    //var result = items.SelectMany(k => values, (k, v) => new {k, v});

    foreach (var key in keys)
    {
        temp = 0;
        tempResults = new List<int>();
        foreach (var item in items)
        {
            if (item.Split(',')[0] == key)
            {
                tempResults.Add(Int32.Parse(item.Split(',')[1]));
                temp++;
            }

            if (temp == size)
            {
                results.Add(new Results
                {
                    Key = key,
                    Values = new List<int>(tempResults)
                });
                temp = 0;
                tempResults.Clear();
            }
        }
    }

    foreach (Results r in results)
    {
        Console.WriteLine("Key: " + r.Key);
        Console.WriteLine("Values: ");
        foreach (int i in r.Values)
        {
            Console.WriteLine(i);
        }
    }

一切正常,但我使用两个循环来获得所需的结果。我想用LINQ表达式替换它们并一直在尝试,但似乎无法弄明白。任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:1)

您可以结合使用LINQ方法:.GroupBy.SelectSelectMany和一些数据结构,例如Tuple<T1, T2>

前提是我们有课程:

class Results
{
    public string Key { get; set; }
    public List<int> Values { get; set; }
}

解决方案可能是:

        int k = 0;
        var result =
            items.Select(x =>                          // parse initial string
                 {
                     var strValue = x.Split(',');
                     return Tuple.Create(strValue[0], Convert.ToInt32(strValue[1]));
                 })
                 .GroupBy(x => x.Item1, y => y.Item2)  // group by key
                 .Select(x => Tuple.Create(x.Key, x))  // flatten to IEnumerable
                 .SelectMany(x =>                      // select fixed size data chunks
                     x.Item2.GroupBy(y => k++ / size, z => z)
                            .Select(z => Tuple.Create(x.Item1, z)))
                 .Select(x =>                          // cast to resulting model type
                     new Results()          
                     {
                         Key = x.Item1,
                         Values = x.Item2.ToList()
                     })
                 .ToList();                            // Return enumeration as list

答案 1 :(得分:0)

不是一种删除内部循环的方法,但您可以使用以下代码缩短代码:

....
var keys = items.Select(t => t.Split(',')[0]).Distinct().ToList();

foreach (var key in keys)
{
    var forKey = items.Where(x => x.Split(',')[0] == key)
                      .Select(k => int.Parse(k.Split(',')[1]));
    for (int x = 0; x < forKey.Count(); x += size)
    {
        results.Add(new Results
        {
            Key = key,
            Values = forKey.Skip(x).Take(size).ToList()
        });
    }
}
....

至少这种方法将消除临时变量和循环内所有if检查的需要,并且还将在结果中包含只有一个整数的A键的最后一个值它的清单。

答案 2 :(得分:0)

如何写一对扩展方法?

const int partitionSize = 2;
var itemLookup = items.ToLookup(x => x.Split(',')[0], x => Int32.Parse(x.Split(',')[1]));
var partitionedItems = itemLookup.Partition(partitionSize);

foreach (var partition in partitionedItems)
foreach (var lookup in partition)
{
    Console.WriteLine("Key: " + lookup.Key);
    Console.WriteLine("Values: ");
    foreach (var i in lookup.ToList())
    {
        Console.WriteLine(i);
    }
}


public static class PartitionExtensions
{
    public static IList<ILookup<K, V>> Partition<K, V>(this ILookup<K, V> lookup, int size)
    {
        return lookup.SelectMany(l => l.ToList().Partition(size).Select(p => p.ToLookup(x => l.Key, x => x))).ToList();
    }

    public static IList<IList<T>> Partition<T>(this IList<T> list, int size)
    {
        IList<IList<T>> results = new List<IList<T>>();
        var itemCount = list.Count();
        var partitionCount = itemCount / size;

        //your paritioning method is truncating items that don't make up a full partition
        //if you want the remaining items in a partial partition, use this code instead
        //var partitionCount = ((itemCount % size == 0) ? itemCount : itemCount + size) / size;

        for (var i = 0; i < partitionCount; i++)
        {
            results.Add(list.Skip(i * size).Take(size).ToList());
        }

        return results;
    }
}