Monday, April 11, 2011

Minimum of a struct-Array in C#

I used a Select() to perform a calculation on each member of an array of structs and now want to have the member for which a certain attribute is minimal. I wanted to use something like Min() on the selected sequence, but I don't know how to return the full struct, rather than only the attribute that is minmal.

From stackoverflow
  • If i understand correctly, i'd say: use delegates...

    Here's an Example from Craig Murphy

    public class Person
    {
              public int age;
              public string name;
              public Person(int age, string name)
              {
                       this.age = age;
                       this.name = name;
              }
    }
    // everyone under 25:
    List<person> young = people.FindAll(delegate(Person p) { return p.age < 25; });
    
    // sort your list: 
    people.Sort(delegate(Person p1, Person p2)
       { return p1.age.CompareTo(p2.age); });
    
  • Sounds like you want to use MinBy from MoreLINQ:

    public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
        Func<TSource, TKey> selector, IComparer<TKey> comparer)
    {
        source.ThrowIfNull("source");
        selector.ThrowIfNull("selector");
        comparer.ThrowIfNull("comparer");
        using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
        {
            if (!sourceIterator.MoveNext())
            {
                throw new InvalidOperationException("Sequence was empty");
            }
            TSource min = sourceIterator.Current;
            TKey minKey = selector(min);
            while (sourceIterator.MoveNext())
            {
                TSource candidate = sourceIterator.Current;
                TKey candidateProjected = selector(candidate);
                if (comparer.Compare(candidateProjected, minKey) < 0)
                {
                    min = candidate;
                    minKey = candidateProjected;
                }
            }
            return min;
        }
    }
    

    ThrowIfNull is defined as an extension method:

    internal static void ThrowIfNull<T>(this T argument, string name)
        where T : class
    {
        if (argument == null)
        {
            throw new ArgumentNullException(name);
        }
    }
    
    Hosam Aly : How is this different from `source.OrderBy(selector, comparer).FirstOrDefault()`?
    configurator : Efficiency. OrderBy is O(n * lg n), this is O(n) I believe.
    Hosam Aly : You're right @configurator. I have just taken a look at the implementation of OrderBy, and I agree. +1 Jon.
  • How about ordering by your "value" and taking the first entry (the minimum value):

    Persons.OrderBy(p => p.Age).FirstOrDefault();
    

    That is of course if you only want one item (which is what you state).

    Alternatively:

    from p in Persons
    where p.Age == Persons.Select(p1 => p1.Age).Min()
    select p;
    

    Will get you all items with minimum value.

    Hosam Aly : +1. I would have done it in the same way (at least for one item).
    Hosam Aly : Jon's answer has better performance, but this one is more "built-in".

0 comments:

Post a Comment