EnumerableFunctions.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // (c) Copyright Microsoft Corporation.
  2. // This source is subject to the Microsoft Public License (Ms-PL).
  3. // Please see http://go.microsoft.com/fwlink/?LinkID=131993] for details.
  4. // All other rights reserved.
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Diagnostics.CodeAnalysis;
  9. using System.Linq;
  10. using System.Reflection;
  11. namespace System.Windows.Controls
  12. {
  13. /// <summary>
  14. /// This class contains general purpose functions to manipulate the generic
  15. /// IEnumerable type.
  16. /// </summary>
  17. internal static class EnumerableFunctions
  18. {
  19. /////// <summary>
  20. /////// Applies a function to an accumulated value and an item in the
  21. /////// sequence and yields the result as the accumulated value.
  22. /////// </summary>
  23. /////// <typeparam name="T">The type of the sequence.</typeparam>
  24. /////// <param name="that">The sequence to scan.</param>
  25. /////// <param name="func">The function applied to the accumulator and the
  26. /////// current item.</param>
  27. /////// <returns>A sequence of computed values.</returns>
  28. ////public static IEnumerable<T> Scan<T>(this IEnumerable<T> that, Func<T, T, T> func)
  29. ////{
  30. //// IEnumerator<T> enumerator = that.GetEnumerator();
  31. //// if (!enumerator.MoveNext())
  32. //// {
  33. //// yield break;
  34. //// }
  35. //// T acc = enumerator.Current;
  36. //// yield return acc;
  37. //// while (enumerator.MoveNext())
  38. //// {
  39. //// acc = func(acc, enumerator.Current);
  40. //// yield return acc;
  41. //// }
  42. ////}
  43. /// <summary>
  44. /// Applies a function to an accumulated value and an item in the
  45. /// sequence and yields the result as the accumulated value.
  46. /// </summary>
  47. /// <typeparam name="T">The type of the input sequence.</typeparam>
  48. /// <typeparam name="R">The type of the initial value.</typeparam>
  49. /// <param name="that">The sequence to scan.</param>
  50. /// <param name="func">The function applied to the accumulator and the
  51. /// current item.</param>
  52. /// <param name="initialValue">The initial value in the output sequence.
  53. /// </param>
  54. /// <returns>A sequence of computed values.</returns>
  55. public static IEnumerable<R> Scan<T, R>(this IEnumerable<T> that, Func<R, T, R> func, R initialValue)
  56. {
  57. R acc = initialValue;
  58. yield return acc;
  59. IEnumerator<T> enumerator = that.GetEnumerator();
  60. while (enumerator.MoveNext())
  61. {
  62. acc = func(acc, enumerator.Current);
  63. yield return acc;
  64. }
  65. }
  66. /// <summary>
  67. /// Accepts two sequences and applies a function to the corresponding
  68. /// values in the two sequences.
  69. /// </summary>
  70. /// <typeparam name="T0">The type of the first sequence.</typeparam>
  71. /// <typeparam name="T1">The type of the second sequence.</typeparam>
  72. /// <typeparam name="R">The return type of the function.</typeparam>
  73. /// <param name="enumerable0">The first sequence.</param>
  74. /// <param name="enumerable1">The second sequence.</param>
  75. /// <param name="func">The function to apply to the corresponding values
  76. /// from the two sequences.</param>
  77. /// <returns>A sequence of transformed values from both sequences.</returns>
  78. public static IEnumerable<R> Zip<T0, T1, R>(IEnumerable<T0> enumerable0, IEnumerable<T1> enumerable1, Func<T0, T1, R> func)
  79. {
  80. IEnumerator<T0> enumerator0 = enumerable0.GetEnumerator();
  81. IEnumerator<T1> enumerator1 = enumerable1.GetEnumerator();
  82. while (enumerator0.MoveNext() && enumerator1.MoveNext())
  83. {
  84. yield return func(enumerator0.Current, enumerator1.Current);
  85. }
  86. }
  87. /// <summary>
  88. /// Returns the index of an item in a sequence.
  89. /// </summary>
  90. /// <typeparam name="T">The type of the sequence.</typeparam>
  91. /// <param name="that">The sequence.</param>
  92. /// <param name="item">The item in the sequence.</param>
  93. /// <returns>The index of an item in a sequence.</returns>
  94. public static int? IndexOf<T>(this IEnumerable<T> that, T item)
  95. {
  96. IEnumerator<T> enumerator = that.GetEnumerator();
  97. int index = 0;
  98. while (enumerator.MoveNext())
  99. {
  100. if (object.ReferenceEquals(enumerator.Current, item))
  101. {
  102. return index;
  103. }
  104. index++;
  105. }
  106. return null;
  107. }
  108. /// <summary>
  109. /// Returns a stream of weighted values based on a percentage.
  110. /// </summary>
  111. /// <param name="values">A sequence of values.</param>
  112. /// <param name="percent">The percentage of values.</param>
  113. /// <returns>A sequence of percentages.</returns>
  114. public static IEnumerable<double> GetWeightedValues(this IEnumerable<double> values, double percent)
  115. {
  116. double total = values.Sum();
  117. if (total == 0)
  118. {
  119. return values.Select(_ => 0.0);
  120. }
  121. return
  122. EnumerableFunctions
  123. .Zip(
  124. values.Scan((acc, current) => acc + current, 0.0),
  125. values,
  126. (acc, current) => Tuple.Create(acc, current))
  127. .Select(tuple => Tuple.Create(tuple.First / total, tuple.Second / total))
  128. .Select(tuple =>
  129. {
  130. double accumulated = tuple.First;
  131. double current = tuple.Second;
  132. if (percent > accumulated && accumulated + current > percent)
  133. {
  134. return (percent - accumulated) * total;
  135. }
  136. else if (percent <= accumulated)
  137. {
  138. return 0.0;
  139. }
  140. else
  141. {
  142. return 1.0;
  143. }
  144. });
  145. }
  146. }
  147. }