1 module app;
2 
3 void main()
4 {
5 	import std.stdio;
6 	import std..string;
7 
8 	writeln(["a", "b", "c"].first!(s => s == "b"));
9 
10 	writeln(["a", "b", "c"].where!(s => s != "a"));
11 
12 	writeln(["A", "B", "C"].select!(s => s.toLower, string));
13 
14 	writeln([6, 77, 2, 86, 15, 65].orderBy!(a => a));
15 }
16 
17 import std.exception;
18 
19 /// Returns the first element in an array that meets the conditionition
20 T first(alias condition = x => true, T)(T[] source)
21 {
22 	enforce(source.length > 0, "Array length cannot be 0");
23 	foreach (k; source)
24 	{
25 		if (condition(k))
26 			return k;
27 	}
28 	return null;
29 }
30 
31 /// Returns the first element in an array that meets the conditionition
32 T firstOrDefault(alias condition = x => true, T)(T[] source)
33 {
34 	enforce(source.length > 0, "Array length cannot be 0");
35 	foreach (k; source)
36 	{
37 		if (condition(k))
38 			return k;
39 	}
40 	return null;
41 }
42 
43 /// Returns the last element in an array that meets the condition
44 T last(alias condition = x => true, T)(T[] source)
45 {
46 	for (int i = source.length; i >= 0; i--)
47 	{
48 		T v = source[i];
49 		if (condition(v))
50 			return v;
51 	}
52 }
53 
54 /// Returns an array of elements that meet the condition 
55 T[] where(alias condition = x => true, T)(T[] source)
56 {
57 	T[] results;
58 	foreach (k; source)
59 	{
60 		if (condition(k))
61 			results ~= k;
62 	}
63 	return results;
64 }
65 
66 /// Checks if array contains one or more item that meets the condition
67 bool any(alias condition = x => true, T)(T[] source)
68 {
69 	foreach (k; source)
70 	{
71 		if (condition(k))
72 			return true;
73 	}
74 	return false;
75 }
76 
77 /// Counts how many items meet the conditions
78 int count(alias condition = x => true, T)(T[] source)
79 {
80 	int i = 0;
81 	foreach (k; source)
82 	{
83 		if (condition(k))
84 			i++;
85 	}
86 	return i;
87 }
88 
89 /// Counts how many items meet the conditions
90 long longCount(alias condition = x => true, T)(T[] source)
91 {
92 	long i = 0;
93 	foreach (k; source)
94 	{
95 		if (condition(k))
96 			i++;
97 	}
98 	return i;
99 }
100 
101 // HACK
102 // TODO
103 // Get rid of TResult and figure out the type from the delegate,
104 // probably use something like ReturnType!selector[] but it doesn't work
105 //
106 // Currently:
107 //   ["a","b","c"].select!(x => x.toLower, string)
108 //
109 // Goal:
110 //   ["a","b","c"].select!(x => x.toLower)
111 
112 /// Selects specified members from objects
113 TResult[] select(alias selector, TResult, TSource)(TSource[] source)
114 {
115 	TResult[] results;
116 	foreach (k; source)
117 	{
118 		results ~= selector(k);
119 	}
120 	return results;
121 }
122 
123 /// Returns an array of distinct items
124 T[] distinct(T)(T[] source)
125 {
126 	T[] results;
127 	foreach (k; source)
128 	{
129 		if (!k in results)
130 			results ~= k;
131 	}
132 	return results;
133 }
134 
135 /// Returns the largest item in the array
136 T max(T)(T[] source)
137 {
138 	T max;
139 	foreach (k; source)
140 	{
141 		if (k > max)
142 			max = k;
143 	}
144 	return max;
145 }
146 
147 /// Returns the smallest item in the array
148 T min(T)(T[] source)
149 {
150 	T min;
151 	foreach (k; source)
152 	{
153 		if (k < min)
154 			min = k;
155 	}
156 	return min;
157 }
158 
159 /// Returns the average value of all items in the array
160 T average(T)(T[] source)
161 {
162 	return source.sum / source.length;
163 }
164 
165 /// Retuns the sum of all values in the array
166 T sum(T)(T[] source)
167 {
168 	foreach (k; source)
169 	{
170 		sum ~= k;
171 	}
172 	return sum / source.length;
173 }
174 
175 /// Sorts the elements of a sequence in ascending order according to a key
176 T[] orderBy(alias func, T)(T[] source)
177 {
178 	import std.algorithm.sorting;
179 
180 	alias compare = (x, y) => func(x) > func(y);
181 	return source.sort!(compare).release;
182 }
183 
184 /// Sorts the elements of a sequence in descending order according to a key
185 T[] orderByDescending(alias func = a => a, T)(T[] source)
186 {
187 	import std.algorithm.sorting;
188 
189 	alias compare = (x, y) => func(x) < func(y);
190 	return source.sort!(compare).release;
191 }