Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing loops with linq code [closed]

Tags:

c#

linq

My current code is like this:

    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);
        }
    }

Everything works fine with it, but I am using two loops to get the results needed. I want to replace them with a LINQ expression and been trying, but can't seem to figure it out. Any help is appreciated.

like image 609
user9248102 Avatar asked Jul 18 '26 21:07

user9248102


2 Answers

You could use a combination of LINQ methods: .GroupBy, .Select, SelectMany and some data structures like Tuple<T1, T2>.

Provided that we have class:

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

The solution could be:

        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
like image 69
Fabjan Avatar answered Jul 21 '26 10:07

Fabjan


How about writing a couple extension methods?

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;
    }
}
like image 20
codeConcussion Avatar answered Jul 21 '26 10:07

codeConcussion



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!