using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace SystemX.Net.Platform.Common.ExtensionMethods { /// /// Linq extension methods /// public static partial class EmLinq { // http://stackoverflow.com/questions/1883920/call-a-function-for-each-value-in-a-generic-c-sharp-collection /// /// Generic IEnumerable ForEach extension : typename T is optional. deducible from source /// /// /// /// public static void ForEach(this IEnumerable source, Action action) { foreach (T item in source) action(item); } public static void Iter(this IEnumerable source, Action action) => ForEach(source, action); public static void Iter(this IEnumerable source, Action action) { int i = 0; foreach (T item in source) action(item, i++); } /// /// Lazy Foreach : Not evaluated until on demand /// public static IEnumerable ForEachTee(this IEnumerable source, Action action) { foreach (T item in source) { action(item); yield return item; } } /// /// Non-Generic IEnumerable ForEach extension : typename T should be provided. /// /// /// /// public static void ForEach(this IEnumerable source, Action action) { foreach (T item in source) action(item); } /// /// Non-Generic IEnumerable ForEach extension : typename T should be provided. /// Lazy Foreach : Not evaluated until on demand /// public static IEnumerable ForEachTee(this IEnumerable source, Action action) { foreach (T item in source) { action(item); yield return item; } } /// /// Non-Generic IEnumerable Select extension : typename T should be provided. /// /// /// /// /// /// public static IEnumerable SelectEx(this IEnumerable source, Func selector) { foreach (TSource item in source) yield return selector(item); } /// /// TResult type 의 enumerable 중에서 TNotCheckType type 이 아닌 것들만 골라서 반환한다. (System.Linq.OfType 의 negation) /// System.Linq.SkipWhile() 구문과 같은 역할 /// TNotCheck 는 TResult type 이어야 함. /// /// enumerable 들의 base type. 동시에 반환될 enumerable 의 type /// 제외할 type /// /// public static IEnumerable OfNotType(this IEnumerable source) where TNotCheckType : TResult { if (source == null) throw new ArgumentNullException("source"); return OfNotTypeIterator(source); } private static IEnumerable OfNotTypeIterator(IEnumerable source) { foreach (object obj in source) { if (!(obj is TNotCheckType)) yield return (TResult)obj; } } /// /// Select Non null element from enumerable /// public static IEnumerable OfNotNull(this IEnumerable source) where TResult : class { if (source == null) throw new ArgumentNullException("source"); foreach (var s in source) { if ( s != null ) yield return s; } } // http://stackoverflow.com/questions/2471588/how-to-get-index-using-linq public static Nullable FindIndex(this IEnumerable items, Predicate predicate) { int index = 0; foreach (var item in items) { if (predicate(item)) return index; index++; } return null; } public static HashSet ToHashSet(this IEnumerable items) { var hash = new HashSet(); items.ForEach(i => hash.Add(i)); return hash; } /// /// 두개의 set 이 동일한지 비교. see SequenceEqual /// public static bool SetEqual(this IEnumerable first, IEnumerable second) { HashSet firstSet = first.ToHashSet(); foreach (var e in second) { if (!firstSet.Contains(e)) return false; } HashSet secondSet = second.ToHashSet(); foreach (var e in first) { if (!secondSet.Contains(e)) return false; } return true; } public static bool RemoveTail(this IList list) { if (list.IsNullOrEmpty()) return false; list.RemoveAt(list.Count - 1); return true; } public static T[] ConcatArrays(params T[][] list) { var result = new T[list.Sum(a => a.Length)]; int offset = 0; for (int x = 0; x < list.Length; x++) { list[x].CopyTo(result, offset); offset += list[x].Length; } return result; } private static Tuple ExtractFirst(this IEnumerable seq) { using (var enumerator = seq.GetEnumerator()) { if (enumerator.MoveNext()) return Tuple.Create(true, enumerator.Current); // => return new Tuple(..) 와 동일 return Tuple.Create(false, default(T)); } } /// /// http://stackoverflow.com/questions/4354902/check-that-all-items-of-ienumerablet-has-the-same-value-using-linq /// public static bool AllEqual(this IEnumerable source, T target) { using (var enumerator = source.GetEnumerator()) { if (!enumerator.MoveNext()) { // empty case return true; } var comparer = EqualityComparer.Default; do { if (!comparer.Equals(target, enumerator.Current)) return false; } while (enumerator.MoveNext()); return true; } } public static bool AllEqual(this IEnumerable source) { var pr = source.ExtractFirst(); if (pr.Item1) return AllEqual(source, pr.Item2); // empty case return true; } public static T Tee(this T input, Action action) { action(); return input; } public static T Tee(this T input, Action action) { action(input); return input; } public static bool ForAll(this IEnumerable source, Func predicate) { foreach (var s in source) { if (!predicate(s)) return false; } return true; } public static bool ForAll(this IEnumerable source, Func predicate) { int i = 0; foreach (var s in source) { if (!predicate(s, i++)) return false; } return true; } public static bool NoForAll(this IEnumerable source, Func predicate) { foreach (var s in source) { if (predicate(s)) return false; } return true; } /// /// source 를 n 개씩 분할한 sequence 를 반환 /// http://stackoverflow.com/questions/419019/split-list-into-sublists-with-linq /// public static IEnumerable> SplitByN(this IEnumerable source, int n) { return source .Select((x, i) => new { Index = i, Value = x }) .GroupBy(x => x.Index / n) .Select(x => x.Select(v => v.Value)) ; } public static IEnumerable EveryNth(this IEnumerable source, int n) { return source.Where((v, i) => i % n == 0); } public static IEnumerable Zip2( this IEnumerable s1, IEnumerable s2, Func resultSelector) => s1.Zip(s2, resultSelector); public static IEnumerable Zip3( this IEnumerable s1, IEnumerable s2, IEnumerable s3, Func resultSelector) { using (var e1 = s1.GetEnumerator()) using (var e2 = s2.GetEnumerator()) using (var e3 = s3.GetEnumerator()) { while (e1.MoveNext() && e2.MoveNext() && e3.MoveNext()) yield return resultSelector(e1.Current, e2.Current, e3.Current); } } public static IEnumerable Zip4( this IEnumerable s1, IEnumerable s2, IEnumerable s3, IEnumerable s4, Func resultSelector) { using (var e1 = s1.GetEnumerator()) using (var e2 = s2.GetEnumerator()) using (var e3 = s3.GetEnumerator()) using (var e4 = s4.GetEnumerator()) { while (e1.MoveNext() && e2.MoveNext() && e3.MoveNext() && e4.MoveNext()) yield return resultSelector(e1.Current, e2.Current, e3.Current, e4.Current); } } public static IEnumerable MinMaxRange(int min, int hop, int max) { if (hop <= 0) throw new ArgumentException("hop counter should be positive."); for (int i = min; i <= max; i += hop) yield return i; } public static IEnumerable MinMaxRange(int min, int max) => Enumerable.Range(min, max - min); public static IEnumerable HexRange(int start, int count) { foreach (var h in Enumerable.Range(start, count)) { yield return $"{h:X}"; } } /// /// Enumerable 의 laziness 를 강제로 실행시켜 evaluation 시킴. /// public static IEnumerable Realize(this IEnumerable seq) { //var count = seq.Count(); // count 만으로는, 즉석 evaluation 이 안되는 경우가 존재...???... var array = seq.ToArray(); return array; } } }