Osvier
Osvier

Reputation: 839

.Net List ForEach Item

I have 2 objects:

public class ClassA
{
   public int Id
   public string name;

   public ClassB myObjectB;

}
public class ClassB
{
   public int Id
   public string name
}

Having 2 Lists for <ClassA> <ClassB> Some items from List1 match by Id with an item on List2... I want to set the objectB foreach item...

foreach(ClassA item in List1)
{
   ClassB obj = (from b in List2 where b.Id == item.Id select b).SingleOrDefault()
   if(obj != null)
   {
       item.myObjectB = obj; 
       ////////break;    <- ignore this
   }
}

This solution works for me, but I'm just wondering if there is a better way to do this, instead of Foreach

Thanks everyone for your help!!!

Upvotes: 2

Views: 9169

Answers (4)

Dave Cousineau
Dave Cousineau

Reputation: 13148

With classes defined as follows:

class ClassA {
   public int Id { get; private set; }
   public string name { get; private set; }

   public ClassB myObjectB { get; set; }

   public ClassA(int pId, string pName) {
      Id = pId;
      name = pName;
   }
}

class ClassB {
   public int Id { get; private set; }
   public string name { get; private set; }

   public ClassB(int pId, string pName) {
      Id = pId;
      name = pName;
   }
}

You can do the following using the LINQ Join method:

var listA = new List<ClassA> {
   new ClassA(1, "OneA"),
   new ClassA(2, "TwoA"),
   new ClassA(3, "ThreeA")
};

var listB = new List<ClassB> {
   new ClassB(1, "OneB"),
   new ClassB(2, "TwoB"),
   new ClassB(4, "FourB")
};

listA
.Join(
   listB,
   itemA => itemA.Id,
   itemB => itemB.Id,
   (itemA, itemB) => new { ItemA = itemA, ItemB = itemB }
).ForEach(pair => pair.ItemA.myObjectB = pair.ItemB);

listA.ForEach(itemA => Console.WriteLine(
   "{0} maps to {1}",
   itemA == null
      ? "null"
      : itemA.name,
   (itemA == null || itemA.myObjectB == null)
      ? "null"
      : itemA.myObjectB.name
));

Output is:

OneA maps to OneB
TwoA maps to TwoB
ThreeA maps to null

Upvotes: 0

caesay
caesay

Reputation: 17213

Expanding on Reed's answer.. You can actually do this in a one-liner, because a list has a ForEach method.

List1.ForEach(item => item.myObjectB = List2.FirstOrDefault(b => b.Id == item.Id) ?? item.myObjectB);

Upvotes: 1

Aaron Anodide
Aaron Anodide

Reputation: 17186

List<ClassA> list1 = new List<ClassA>();
List<ClassB> list2 = new List<ClassB>();

list1.Add(new ClassA { Id = 2, name = "a2" });
list1.Add(new ClassA { Id = 3, name = "a3" });
list1.Add(new ClassA { Id = 4, name = "a4" });
list1.Add(new ClassA { Id = 5, name = "a5" });

list2.Add(new ClassB { Id = 1, name = "b1" });
list2.Add(new ClassB { Id = 2, name = "b2" });
list2.Add(new ClassB { Id = 4, name = "b4" });
list2.Add(new ClassB { Id = 5, name = "b5" });

// Goal is to set ClassA::myObjectB from List1 to 
// matching instance (if any) of ClassB from List2
var query = 
    from a in list1
    from b in list2
    where a.Id == b.Id
    select Tuple.Create(a, b);  
foreach (var element in query)
    element.Item1.myObjectB = element.Item2;

Update:

Or if you really don't want a for loop, I just realized you can use the fact that assignments return a value and at the same time make an entry in an obfuscated code contest :)

(from a in list1
 from b in list2
 where a.Id == b.Id
 select a.myObjectB = b).ToList();

Update2:

I just thought of an alternate approach - depending on your scenario, a lazy mechanism might work for you?

public class ClassA
{
   public int Id
   public string name;

   private ClassB myObjectB;
   public ClassB MyObjectB { 
      get { return myObjectB ?? (myObjectB = list2.FirstOrDefault(x => this.Id == x.Id)); } 
   }
}

Upvotes: 0

Reed Copsey
Reed Copsey

Reputation: 564413

I think that a foreach, in this case, is actually the appropriate approach, as you're mutating your list. You could potentially simplify your code a bit, however:

foreach(ClassA item in List1)
{
    item.myObjectB = List2.FirstOrDefault(b => b.Id == item.Id);
}

This will set the item every time, though it will be set to null if there is no match. If you already have items in myObjectB and setting them to null is inappropriate, you could use:

foreach(ClassA item in List1)
{
    item.myObjectB = List2.FirstOrDefault(b => b.Id == item.Id) ?? item.myObjectB;
}

Upvotes: 8

Related Questions