j.heidt

Avoid 287at all costs
posts - 14, comments - 11, trackbacks - 1

Fun 2.0 list methods

I was working on some code at work that was using the 2.0 framework and COM interop, and in the course of adding enumerator capability to the old COM code, I worked up a quick Lists.cs static class that does some useful things on IEnumerable<T> classes.

The methods are heavily inspired from the MooTools Array API

/// <summary>
/// Static helper functions for dealing with enumerable items. 
/// The design of these helper methods was inspired in part by the mootools array library.
/// </summary>
public static class Lists {
    /// <summary>
    /// Calls a the provided function for each element in the list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    public static void Each<T>(IEnumerable<T> list, Action<T> func) {
        foreach (T item in list) {
            func(item);
        }
    }

    /// <summary>
    /// Whiles the specified list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="condition">The condition.</param>
    /// <param name="func">The func.</param>
    public static void While<T>(IEnumerable<T> list, Predicate<T> condition, Action<T> func) {
        foreach (T item in list) {
            if (!condition(item))
                return;
            func(item);
        }
    }

    /// <summary>
    /// Returns true if every element in the list satisfies the provided testing function. 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    /// <returns></returns>
    public static bool Every<T>(IEnumerable<T> list, Predicate<T> func) {
        bool called = false;
        foreach (T item in list) {
            called = true;
            if (!func(item)) {
                return false;
            }
        }
        return called;
    }

    /// <summary>
    /// Creates a new list with all of the elements of the list for which the provided filtering function returns true. 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    /// <returns></returns>
    public static IEnumerable<T> Filter<T>(IEnumerable<T> list, Predicate<T> func) {
        foreach (T item in list) {
            if (func(item)) {
                yield return item;
            }
        }
    }

    /// <summary>
    /// Creates a new list with all of the elements of the source list which are not the default for the list item type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <returns></returns>
    public static IEnumerable<T> Clean<T>(IEnumerable<T> list) {
        foreach (T item in list) {
            if (!Equals(item, default(T))) {
                yield return item;
            }
        }
    }

    /// <summary>
    /// Returns a list with the results of calling a provided function on every element in the source list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    /// <returns></returns>
    public static IEnumerable<T> Map<T>(IEnumerable<T> list, Converter<T, T> func) {
        foreach (T item in list) {
            yield return func(item);
        }
    }

    /// <summary>
    /// Returns a list with the results of calling a provided function on every element in the source list.
    /// </summary>
    /// <typeparam name="TInput">The type of the input.</typeparam>
    /// <typeparam name="TOutput">The type of the output.</typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The converter function.</param>
    /// <returns></returns>
    public static IEnumerable<TOutput> Convert<TInput, TOutput>(IEnumerable<TInput> list, Converter<TInput, TOutput> func) {
        foreach (TInput item in list) {
            yield return func(item);
        }
    }

    /// <summary>
    /// Returns true if at least one element in the source list satisfies the provided testing function.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="func">The func.</param>
    /// <returns></returns>
    public static bool Some<T>(IEnumerable<T> list, Predicate<T> func) {
        foreach (T item in list) {
            if (func(item)) {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// Returns a list of key-value pairs based on the list of keys passed in and the items in the source list.
    /// </summary>
    /// <typeparam name="K">The Key type</typeparam>
    /// <typeparam name="V">The Value type</typeparam>
    /// <param name="keys">The list of keys.</param>
    /// <param name="list">The list of values.</param>
    /// <returns></returns>
    public static IEnumerable<KeyValuePair<K, V>> Link<K, V>(IEnumerable<K> keys, IEnumerable<V> list) {
        using (var keyIterator = keys.GetEnumerator()) {
            using (var valueIterator = list.GetEnumerator()) {
                while (keyIterator.MoveNext() &&
                       valueIterator.MoveNext()) {
                    yield return new KeyValuePair<K, V>(keyIterator.Current, valueIterator.Current);
                }
            }
        }
    }

    /// <summary>
    /// Tests the list for the presence of an item.
    /// </summary>
    /// <typeparam name="T">The item types in the list, this type must be equatable to itself</typeparam>
    /// <param name="list">The list.</param>
    /// <param name="item">The item.</param>
    /// <returns>
    ///     <c>true</c> if the specified list contains the item; otherwise, <c>false</c>.
    /// </returns>
    public static bool Contains<T>(IEnumerable<T> list, T item) where T : IEquatable<T> {
        foreach (T val in list) {
            if (Equals(val, item)) {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// Extends a list with all the items of another list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="additions">The additions.</param>
    /// <returns></returns>
    public static IEnumerable<T> Extend<T>(IEnumerable<T> list, params IEnumerable<T>[] additions) {
        foreach (T item in list) {
            yield return item;
        }
        foreach (IEnumerable<T> exList in additions) {
            foreach (T item in exList) {
                yield return item;
            }
        }
    }
}
 
And here is some of the unit test code I did to explain some of the methods if they aren't clear:
 
[TestFixture]
public class ListsTests {

        public string[] FirstNames;
        public string[] LastNames;

        [TestFixtureSetUp]
        public void Init() {
            FirstNames = new[] {"jake", "chris", "jason", "bass", "brian", "russ"};
            LastNames = new[] {"heidt", "oliver", "torres", "bassalino", "dorry", "guzetta"};
        }

        [Test]
        public void Clean() {
            string[] clean_list = new[] {null, null, "some", "strings up in this", null};
            int itemsReturned = 0;
            foreach (string x in Lists.Clean(clean_list)) {
                Assert.IsNotNull(x);
                itemsReturned++;
            }

            Assert.IsTrue(itemsReturned == 2);
        }

        [Test]
        public void Contains() {
            Assert.IsTrue(Lists.Contains(FirstNames, "jake"));
            Assert.IsTrue(Lists.Contains(FirstNames, "chris"));
            Assert.IsTrue(Lists.Contains(FirstNames, "jason"));
            Assert.IsTrue(Lists.Contains(FirstNames, "bass"));
            Assert.IsTrue(Lists.Contains(FirstNames, "brian"));
            Assert.IsTrue(Lists.Contains(FirstNames, "russ"));
            Assert.IsFalse(Lists.Contains(FirstNames, "RUSS"));
        }

        [Test]
        public void Each() {
            int firstNamesWithEvenLetters = 0;
            Lists.Each(FirstNames, delegate(string x) {
                                       if (x.Length % 2 == 0) {
                                           firstNamesWithEvenLetters++;
                                       }
                                   });

            Assert.IsTrue(firstNamesWithEvenLetters == 3); // jake, bass, russ
        }

        [Test]
        public void Every() {
            /* test that each name contains a vowel, using Lists.Every */
            Assert.IsTrue(
                Lists.Every(FirstNames, delegate(string x) { return x.IndexOfAny("aeiou".ToCharArray()) > 0; // contains a vowel
                                        })
                );
        }

        [Test]
        public void Extend() {
            int targetCount = 0;
            int extendCount = 0;

            IEnumerable<string> fNames = FirstNames;
            IEnumerable<string> lNames = LastNames;
            foreach (string name in fNames) {
                targetCount++;
            }
            foreach (string name in lNames) {
                targetCount++;
            }


            IEnumerable<string> bothNameParts = Lists.Extend(fNames, lNames);
            foreach (string name in bothNameParts) {
                extendCount++;
            }

            Assert.IsTrue(targetCount == extendCount);
        }

        [Test]
        public void Filter() {
            IEnumerable<string> evenNames = Lists.Filter(FirstNames, delegate(string x) { return x != null && x.Length % 2 == 0; });
            foreach (string name in evenNames) {
                Trace.WriteLine(string.Format(".Filter -> name: {0}", name));
                Assert.IsNotNull(name);
                Assert.IsTrue(name.Length % 2 == 0);
            }
        }

        [Test]
        public void Link() {
            IEnumerable<KeyValuePair<string, string>> firstLastNameDict = Lists.Link(FirstNames, LastNames);
            foreach (KeyValuePair<string, string> pair in firstLastNameDict) {
                Assert.IsNotNull(pair);
                Assert.IsNotNull(pair.Key);
                Assert.IsNotNull(pair.Value);
                if (pair.Key == "jake") {
                    Assert.IsTrue(pair.Value == "heidt");
                }
                if (pair.Key == "russ") {
                    Assert.IsTrue(pair.Value == "guzetta");
                }
            }
        }

        [Test]
        public void Map() {
            // convert/format each item in the source list to an upper case string.
            IEnumerable<string> upperCaseName = Lists.Map(FirstNames,
                                                          delegate(string x) { return x.ToUpper(); }
                );

            Regex rxUpperCaseOnly = new Regex("^[A-Z ]+$"); // regex test for upper case letters and spaces only
            foreach (string name in upperCaseName) {
                Assert.IsNotNull(name);
                Assert.IsTrue(rxUpperCaseOnly.IsMatch(name));
            }
        }

        [Test]
        public void Some() {
            Assert.IsTrue(Lists.Some(FirstNames, delegate(string x) { return x.Contains("eidt"); }));
        }

        [Test]
        public void Example() {

        }
    }

Print | posted on Wednesday, August 13, 2008 4:17 PM |

Feedback

No comments posted yet.

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 7 and 1 and type the answer here:

Powered by: