-1

So I have this list, it returns an ID and a thumbnail. ex. List<PersonPicture> and I have this list, List<Person> which has a property named "picture" in it. Is there anyway that I can merge this two properties and add the List<PersonPicture> to the property named "picture" in it and base this via the ID since they have the same?

Any help would be appreciated.

Nathan
  • 1,520
  • 1
  • 12
  • 21

4 Answers4

2

You can use an anonymous object for this, below an example:

List<PersonPicture> pictures = LoadPictures();
List<Person> persons = LoadPersons();

var result = persons.Select(pers => new
{
  Id = pers.Id,
  Name = pers.Name,
  Picture = pictures.Where(pic => pic.PersId == pers.Id)
    .FirstOrDefault()
    .Thumbnail
};

Another solution is to use a Join:

var result = persons.Join(pictures, 
  pers => pers.Id, 
  pic => pic.PersId,
  (pers, pic) => { 
    return new
    {
      Id = pers.Id,
      Name = pers.Name,
      Picture = pic.Thumbnail
    };
  });
Erwin
  • 4,757
  • 3
  • 31
  • 41
  • why is foreach faster on execution than this? I am trying to optimize my foreach statement and linq did not help. – Nathan Oct 01 '12 at 19:01
2

LINQ isn't quite designed for modifying existing collections like this, but you can do it:

foreach (tup in people
    .Join(
        picture,
        person => person.ID,
        picture => picture.ID,
        Tuple.Create
    ))
{
    tup.Item1.Picture = tup.Item2;
}

EDIT: Note that this will produce unpredictable results if a person has more than one picture. Is this a possibility, and how should it be dealt with?

Thom Smith
  • 13,916
  • 6
  • 45
  • 91
0

You could either use a Join or the Zip operator in linq. These links will take you to questions about the syntax of using both of them. Basically the Join just adds the two lists together based on a key just like in SQL and the Zip merges the two lists by matching the position of each element in each list..

Community
  • 1
  • 1
specificityy
  • 580
  • 1
  • 5
  • 24
0

You want to join the two lists based on a shared key -- the ID.

Basically, you want to use the Join operator in LINQ to find pairs of Person and PersonPicture that match the same ID:

    persons.Join(pictures, // join these two lists 
        person => person.Id, // extract key from person
        personPicture => personPicture.PersonId, // extract key from picture
        (person, personPicture) => ??? // do something with each matching pair

The question you now face is what to do with each matching pair; Join lets you supply a delegate that takes a matching pair and returns something else, and the result of the Join operation will be a list of those 'something else's produced from each of the matching pairs.

Your problem is that you want to take each pair and do something with it -- specifically, you want to copy the picture from the PersonPicture object to the Person object. Since LINQ is all about finding data but not modifying it, this is not trivial.

You can do this in two ways. One is to create a temporary object from each pair, and then iterate over that and do your thing:

    var pairs = persons.Join(pictures, 
        person => person.Id, 
        personPicture => personPicture.PersonId,
        (person, personPicture) => new { person, personPicture };

    foreach (var pair in pairs) 
        pair.person.Picture = pair.personPicture.Thumbnail;

(You can use a Tuple instead of a temporary object, as was suggested in another answer).

This works, but seems clumsy because of the temporary object (be it an anonymous object or a tuple).

Alternatively, you can do the assignment right inside the delegate, and return the Person object itself, since you're done with the PersonPicture object:

    var personsWithPicturesPopulated = persons.Join(pictures, 
        person => person.Id, 
        personPicture => personPicture.PersonId,
        (person, personPicture) => { 
             person.Picture = personPicture.Thumbnail; 
             return person;
        });

This has the added bonus of giving you the list of persons for which you found a match in the personPictures list, omitting the ones without a match; this is sometimes exactly what you need (and other times it isn't, in which case you can discard the result of the join).

Avish
  • 4,516
  • 19
  • 28
  • why is foreach faster on execution than this? I am trying to optimize my foreach statement and linq did not help. – Nathan Oct 01 '12 at 19:00
  • 1
    I don't quite follow you. What are you `foreach`-ing over which is faster? If you're doing a nested foreach (e.g. foreach person, foreach personPicture, if p.id==pp.id then p.picture=pp.picture) then theoretically for large lists it should be **slower** than using Join -- computationally speaking, nested foreach is O(n*m) while Join is O(n+m) since it uses a hash table under the hood. For small lists, nested foreach might be slightly faster due to less overhead, but this difference should be negligible. – Avish Oct 01 '12 at 19:20
  • Maybe you could post your `foreach` solution and ask why it's faster as an edit to this question (or maybe as a new one)? – Avish Oct 01 '12 at 19:22