Skip to content

Instantly share code, notes, and snippets.

@slavbar
Last active May 15, 2020 13:55
Show Gist options
  • Select an option

  • Save slavbar/3348a3a4d6753c8ca3a867d9cc2e445d to your computer and use it in GitHub Desktop.

Select an option

Save slavbar/3348a3a4d6753c8ca3a867d9cc2e445d to your computer and use it in GitHub Desktop.

EasySharp extensions

DistinctBy

    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
      this IEnumerable<TSource> source,
      Func<TSource, TKey> keySelector)
    {
      HashSet<TKey> hash = new HashSet<TKey>();
      return source.Where<TSource>(p => hash.Add(keySelector(p)));
    }
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
      this IEnumerable<TSource> source,
      Func<TSource, TKey> keySelector)
    {
      return source.GroupBy(x => keySelector(x)).Select(g => g.First());
    }

Combinatorics

    public class Combinatorics
    {
        public static IEnumerable<IEnumerable<T>> GetArrangements<T>(IEnumerable<T> collection, int? granularityDepth = null)
        {
            var items = collection.ToList();
            var arrangementsStack = new Stack<IEnumerable<T>>();
            GetArrangements(items, granularityDepth ?? items.Count, arrangementsStack);
            return arrangementsStack;
        }

        private static IEnumerable<IEnumerable<T>> GetArrangements<T>(List<T> collection, int depth, Stack<IEnumerable<T>> stack)
        {
            if (depth == 1)
            {
                stack.Push(collection);
                return new [] { collection };
            }

            var crossArrangements = GetArrangements(collection, depth - 1, stack);

            var uniqueSequences =  new List<IEnumerable<T>>();
            crossArrangements.SelectMany(
                    sequence => sequence,
                    (sequence, item) => sequence.Except(new[] { item }))
                .ToList().ForEach(arrangement =>
                {
                    var enumeratedArrangement = arrangement.ToList();
                    var isSequenceUnique = !stack.Any(sequence => sequence.OrderBy(x => x)
                        .SequenceEqual(enumeratedArrangement.OrderBy(x => x)));

                    if (isSequenceUnique)
                    {
                        stack.Push(enumeratedArrangement);
                        uniqueSequences.Add(enumeratedArrangement);
                    }
                });

            return uniqueSequences;
        }

        public static IEnumerable<IEnumerable<T>> GetPermutationsDownToMinimalGroup<T>(
            List<T> collection, int? granularity = null)
        {
            return Enumerable.Range(1, granularity ?? collection.Count)
                .Select(groupSize => GetPermutations(collection, groupSize).ToList())
                .SelectMany(sequence => sequence);
        }

        public static IEnumerable<IEnumerable<T>> GetPermutations<T>(List<T> collection, int? groupSize = null)
        {
            return GetPermutations(collection, groupSize ?? collection.Count);
        }

        private static IEnumerable<IEnumerable<T>> GetPermutations<T>(List<T> collection, int groupSize)
        {
            if (groupSize == 1)
            {
                return collection.Select(item => new[] { item });
            }

            var permutations = GetPermutations<T>(collection, groupSize - 1);
            return permutations.SelectMany(
                sequence => collection.Where(item => !sequence.Contains(item)),
                (sequence, item) => sequence.Concat(new[] { item })).ToList();
        }
    }

Working with NameValueCollection

public static class NamedValueCollectionExtensions
{
    public static IEnumerable<KeyValuePair<string, string[]>> AsEnumerable( this NameValueCollection that )
    {
        return that
            .Cast<string>() // doesn't implement IEnumerable<T>, but does implement IEnumerable
            .Select( ( item, index ) => // enable indexing by integer rather than string
                new KeyValuePair<string, string[]>( item, that.GetValues( index ) ) ); // if you use the indexer or GetValue it flattens multiple values for a key, Joining them with a ',' which we don't want
    }

    public static IEnumerable<KeyValuePair<string, string>> AsKeyValuePairs( this IEnumerable<KeyValuePair<string, string[]>> that )
    {
        return that
            .SelectMany( item =>
                item.Value.Select( value =>
                    new KeyValuePair<string, string>( item.Key, value ) ) );
    }

    public static NameValueCollection ToNameValueCollection( this IEnumerable<KeyValuePair<string, string[]>> that )
    {
        return that.AsKeyValuePairs().ToNameValueCollection();
    }

    public static NameValueCollection ToNameValueCollection( this IEnumerable<KeyValuePair<string, string>> that )
    {
        var result = new NameValueCollection();
        foreach ( KeyValuePair<string, string> item in that )
            result.Add( item.Key, item.Value );
        return result;
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment