Jimmy
Jimmy

Reputation: 3264

Enumerating two collections

class MyClass
{
string identifier;
}

I have two lists of identical count

List<MyClass> myClassList;
List<string> identifierList;

I would like to know what is the best way of assigning identifier in the myClassList enumerating over identifierList?

I wrote this, but looks too long(and inefficient?). There must be a better way of doing this?

identifierList.Select((value,index)=>new {value, index}).ToList().ForEach(x=> myClassList[x.index].identifier = x.value);

Upvotes: 2

Views: 85

Answers (3)

Fabjan
Fabjan

Reputation: 13676

Well, how about simple query like this.

myClassList.Select((e, i) => { e.identifier = identifierList[i]; return e; }).ToList();

We need this .ToList() to execute the query, otherwise it'll just do nothing.

Example :

        List<string> identifierList = new List<string>()
        {
            "abc", "def", "ghi"
        };

        List<MyClass> myClassList = new List<MyClass>()
        {
            new MyClass(), new MyClass(), new MyClass(),
        };

        myClassList.Select((e, i) => { e.Id = identifierList[i]; return e; }).ToList();

        foreach (var item in myClassList)
            Console.Write(item.Id + "  ");

Output : abc def ghi

In case your collections are of different length you can use :

myClassList.Select((e, i) => { e.Id = i < identifierList.Count? identifierList[i] : e.Id; return e; }).ToList();

Upvotes: 0

Sean
Sean

Reputation: 62522

You can use Zip:

myClassList.Zip(identifierList, (klass, id) =>
{
  klass.identifier = id;
  return klass
});

Note that this will give you a mutating Linq expression.

However, I suspect this is probably clearer:

for(int i = 0; i < myClassList.Count; i++)
{
  myClassList[i].identifier = identifierList[i];
}

It may not be as "hip" as using Linq, but it's easier to read and understand what's going on!

Upvotes: 1

Tim Schmelter
Tim Schmelter

Reputation: 460238

Yes, you're approach is inefficient(you're creating a throwaway list) and not very readable and also throws an exception if both lists have a different size.

You're looking for the Enumerable.Zip extension method which joins by index:

var zipped = myClassList.Zip(identifierList, (c, s) => new { class = c, string = s});
foreach(var x in zipped)
    x.class.identifier = x.string;

Upvotes: 2

Related Questions