1 module dlq;
2 
3 unittest
4 {
5 	import std.stdio;
6 	import std..string;
7 
8 	assert(["a", "b", "c"].first!(s => s == "b") == "b");
9 	assert(["a","a","b","b"].distinct == ["a", "b"]);
10 }
11 import std.exception;
12 
13 /// Returns the first element in an array that meets the conditionition
14 T first(alias condition = x => true, T)(T[] source)
15 {
16 	enforce(source.length > 0, "Array length cannot be 0");
17 	foreach (k; source)
18 	{
19 		if (condition(k))
20 			return k;
21 	}
22 	return null;
23 }
24 
25 /// Returns the first element in an array that meets the conditionition
26 T firstOrDefault(alias condition = x => true, T)(T[] source)
27 {
28 	enforce(source.length > 0, "Array length cannot be 0");
29 	foreach (k; source)
30 	{
31 		if (condition(k))
32 			return k;
33 	}
34 	return null;
35 }
36 
37 /// Returns the last element in an array that meets the condition
38 T last(alias condition = x => true, T)(T[] source)
39 {
40 	for (int i = source.length; i >= 0; i--)
41 	{
42 		T v = source[i];
43 		if (condition(v))
44 			return v;
45 	}
46 }
47 
48 /// Returns an array of elements that meet the condition 
49 T[] where(alias condition = x => true, T)(T[] source)
50 {
51 	T[] results;
52 	foreach (k; source)
53 	{
54 		if (condition(k))
55 			results ~= k;
56 	}
57 	return results;
58 }
59 
60 /// Checks if array contains one or more item that meets the condition
61 bool any(alias condition = x => true, T)(T[] source)
62 {
63 	foreach (k; source)
64 	{
65 		if (condition(k))
66 			return true;
67 	}
68 	return false;
69 }
70 
71 /// Counts how many items meet the conditions
72 int count(alias condition = x => true, T)(T[] source)
73 {
74 	int i = 0;
75 	foreach (k; source)
76 	{
77 		if (condition(k))
78 			i++;
79 	}
80 	return i;
81 }
82 
83 /// Counts how many items meet the conditions
84 long longCount(alias condition = x => true, T)(T[] source)
85 {
86 	long i = 0;
87 	foreach (k; source)
88 	{
89 		if (condition(k))
90 			i++;
91 	}
92 	return i;
93 }
94 
95 // HACK
96 // TODO
97 // Get rid of TResult and figure out the type from the delegate,
98 // probably use something like ReturnType!selector[] but it doesn't work
99 //
100 // Currently:
101 //   ["a","b","c"].select!(x => x.toLower, string)
102 //
103 // Goal:
104 //   ["a","b","c"].select!(x => x.toLower)
105 
106 /// Selects specified members from objects
107 TResult[] select(alias selector, TResult, TSource)(TSource[] source)
108 {
109 	TResult[] results;
110 	foreach (k; source)
111 	{
112 		results ~= selector(k);
113 	}
114 	return results;
115 }
116 
117 /// Returns an array of distinct items
118 T[] distinct(T)(T[] source)
119 {
120 	T[] results;
121 	foreach (k; source)
122 	{
123 		if (!(results.contains(k)))
124 			results ~= k;
125 	}
126 	return results;
127 }
128 
129 /// Check if an array contains an item
130 bool contains(T)(T[] source, T item)
131 {
132 	return source.any!(i => i == item);
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 }