Assign values from one list to another using LINQ

35,970

Solution 1

I would just build up a dictionary and use that:

Dictionary<int, string> map = sourceList.ToDictionary(x => x.Id, x => x.Name);

foreach (var item in destinationList)
    if (map.ContainsKey(item.Id))
        item.Name = map[item.Id];

destinationList.RemoveAll(x=> x.Name == null);

Solution 2

Hope this will your desired result. First join two list based on key(Id) and then set property value from sourceList.

        var result = destinationList.Join(sourceList, d => d.Id, s => s.Id, (d, s) =>
        {
            d.Name = s.Name;
            return d;
        }).ToList();

Solution 3

Barring the last requirement of "avoid creating new destinationList" this should work

var newList = destinationList.Join(sourceList, d => d.Id, s => s.Id, (d, s) => s);

To take care of "avoid creating new destinationList", below can be used, which is not any different than looping thru whole list, except that it probably is less verbose.

destinationList.ForEach(d => {
                               var si = sourceList
                                           .Where(s => s.Id == d.Id)
                                           .FirstOrDefault();
                               d.Name = si != null ? si.Name : "";
                             });
destinationList.RemoveAll(d => string.IsNullOrEmpty(d.Name));
Share:
35,970
user1269810
Author by

user1269810

Updated on July 05, 2022

Comments

  • user1269810
    user1269810 almost 2 years

    Hello I have a little problem with assigning property values from one lists items to anothers. I know i could solve it "the old way" by iterating through both lists etc. but I am looking for more elegant solution using LINQ.

    Let's start with the code ...

    class SourceType
    {
        public int Id;
        public string Name;
        // other properties
    }
    
    class DestinationType
    {
        public int Id;
        public string Name;
        // other properties
    }
    
    List<SourceType> sourceList = new List<SourceType>();
    sourceList.Add(new SourceType { Id = 1, Name = "1111" });
    sourceList.Add(new SourceType { Id = 2, Name = "2222" });
    sourceList.Add(new SourceType { Id = 3, Name = "3333" });
    sourceList.Add(new SourceType { Id = 5, Name = "5555" });
    
    List<DestinationType> destinationList = new List<DestinationType>();
    destinationList.Add(new DestinationType { Id = 1, Name = null });
    destinationList.Add(new DestinationType { Id = 2, Name = null });
    destinationList.Add(new DestinationType { Id = 3, Name = null });
    destinationList.Add(new DestinationType { Id = 4, Name = null });
    

    I would like to achieve the following:

    • destinationList should be filled with Names of corresponding entries (by Id) in sourceList
    • destinationList should not contain entries that are not present in both lists at once (eg. Id: 4,5 should be eliminated) - something like inner join
    • I would like to avoid creating new destinationList with updated entries because both lists already exist and are very large, so no "convert" or "select new".

    In the end destinationList should contain:

    1 "1111"
    2 "2222"
    3 "3333"
    

    Is there some kind of elegant (one line Lambda? ;) solution to this using LINQ ?

    Any help will be greatly appreciated! Thanks!

  • BrokenGlass
    BrokenGlass about 12 years
    This is O(n^2) - use a dictionary for lookup instead
  • amit_g
    amit_g about 12 years
    @BrokenGlass, you mean O(n). The dictionary lookup should be much faster even with insertion. Ideally these lists should probably be dictionary to begin with (assuming Id are unique).
  • user1269810
    user1269810 about 12 years
    @amit_g - I experimented with join, very interesting, but i couldn't further assign the corresponding name. The second is also interesting...
  • amit_g
    amit_g about 12 years
    What do you mean by "i couldn't further assign the corresponding name."? The first one is selecting the source that already has Name in it. Please note that these are not the most efficient way of doing it if the lists are very long. If you have very long lists, use answer posted by @BrokenGlass or at least perform benchmarks.
  • BrokenGlass
    BrokenGlass about 12 years
    @amit_g: I didn't mean O(n) - your code is O(n^2) since you do a Foreach = O(n) and a nested Where(..) which is also O(n) -> so it's O(n^2)
  • user1269810
    user1269810 about 12 years
    @amit_g - Well yes but this Join returns sourceList with Name, I need destinationList to be filled with that corresponding Name from source. But anyways this is an interesting example :)
  • user1269810
    user1269810 about 12 years
    Hmm, yes, this looks very promising! You are right, performance is at stake here. Seems like the best answer to my problem, I'll explore it further. Thanks!
  • amit_g
    amit_g about 12 years
    @user1269810, the first method is not modifying any list but is creating a new one and returning it. So you could do destinationList = destinationList.Join(...) but regardless of how it is written, in that method, the existing lists are not modified, a new one is created.
  • user1269810
    user1269810 about 12 years
    @amit_g - Okay, well, one cannot have everything :)
  • user1269810
    user1269810 about 12 years
    OK, this is it. Not exactly what I imagined but it works perfectly. Thank you!
  • Milind Thakkar
    Milind Thakkar almost 6 years
    This saved my day ! Thanks !!