tags:

views:

146

answers:

5

Say we have a list {a, a, a, b, b, c, c }

We want to loop through the list and make some kind of change when the item value changes... for example:

prevEmployer = String.empty;
foreach(Person p in PersonList){
  if(p.Employer != prevEmployer){ 
    doSomething(); 
    prevEmployer = p.Employer;
  }
  ... more code
}

Is there any alternative to this? It just looks cludgy to me.

Edit: made the code more realistic to the problem at hand.

A: 

You could just get the distinct values out of the array?

Matt Grande
+5  A: 

Do you want the distinct values? i.e. will there ever be {a,a,a,b,b,a,c,c,a}? If not, you could use LINQ:

foreach(string s in theList.Distinct()) {
   doSomething(); // with s
}


Re your update; perhaps use something like DistinctBy:

foreach(var item in data.DistinctBy(x=>x.Foo)) {
    Console.WriteLine(item.Bar);
}

public static IEnumerable<TSource> DistinctBy<TSource,TValue>(
        this IEnumerable<TSource> source, Func<TSource,TValue> selector) {
    var set = new HashSet<TValue>();
    foreach (var item in source) {
        if (set.Add(selector(item))) {
            yield return item;
        }
    }
}
Marc Gravell
Sorry, I should have clarified - I do not want distinct values. This is a very simple example, I'm actually comparing a property of an object in the loop (and it is sorted by that property)
cleverswine
I'll swap my example for "DistinctBy"...
Marc Gravell
A: 

Looks good to me as long as String.Empty is never an element of your list and your list is sorted. May want to make sure theList isn't mutated by some other thread. Looks like a pretty stock way to handle work on a transition in the list...

Arnshea
+3  A: 

This really depends on what you are trying to do with the rest of the code. @Marc Gravell's response is correct if you only need to perform an action for each distinct element in the list, however, if doSomething() just sets up some state based on the fact that list element has changed and you are operating on each element in the list (or need the individual elements for another purpose), then your method seems perfectly reasonable.

tvanfosson
I need to perform actions on every item in the list, but need to reinitialize something when a certain property of the object changes. I think the simple, cludgy way may be the best after all.
cleverswine
A: 

I decided to go with the following solution, which is much prettier but results in more db calls.

foreach(Employer employer in EmployerList){
  ProcessEmployees(employer);
}

ProcessEmployees(Employer employer){
  EmployeeList = GetEmployees(employer);
  foreach(Employee employee in EmployeeList){
    doStuff...
  }
}

So instead of starting with {a, a, a, b, b, c, c }, I'll be processing {a, a, a} {b, b} {c, c}

cleverswine
You do know you could just do that with:foreach (var employeeGroup in EmployeeList.GroupBy(employee => employee.Employer) foreach (var employee in employeeGroup)The inner foreach loop loops over all the employees in the employer. employeeGroup.Key is the employer
Niki
I didn't know about GroupBy - that's pretty sweet. I think that solves my original problem without the refactoring that I ended up doing. I have to try it now :)
cleverswine
Oh, it's a LINQ thing. I'm not ready to throw LINQ into the code base at 3pm on a Friday. For reference, there's a decent example on MSDN: http://msdn.microsoft.com/en-us/library/bb534304.aspx
cleverswine