array_tool/vec.rs
1// Copyright 2015-2017 Daniel P. Clark & array_tool Developers
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8/// Several different methods for getting, or evaluating, uniqueness.
9pub trait Uniq<T> {
10 /// `uniq` returns a vector of unique values within itself as compared to
11 /// the other vector which is provided as an input parameter.
12 ///
13 /// # Example
14 /// ```
15 /// use array_tool::vec::Uniq;
16 ///
17 /// vec![1,2,3,4,5,6].uniq( vec![1,2,5,7,9] );
18 /// ```
19 ///
20 /// # Output
21 /// ```text
22 /// vec![3,4,6]
23 /// ```
24 fn uniq(&self, other: Self) -> Self;
25
26 /// `unique` removes duplicates from within the vector and returns Self.
27 ///
28 /// # Example
29 /// ```
30 /// use array_tool::vec::Uniq;
31 ///
32 /// vec![1,2,1,3,2,3,4,5,6].unique();
33 /// ```
34 ///
35 /// # Output
36 /// ```text
37 /// vec![1,2,3,4,5,6]
38 /// ```
39 fn unique(&self) -> Self;
40
41 /// `is_unique` returns boolean value on whether all values within
42 /// Self are unique.
43 ///
44 /// # Example
45 /// ```
46 /// use array_tool::vec::Uniq;
47 ///
48 /// vec![1,2,1,3,4,3,4,5,6].is_unique();
49 /// ```
50 ///
51 /// # Output
52 /// ```text
53 /// false
54 /// ```
55 fn is_unique(&self) -> bool;
56
57 /// `uniq_via` returns a vector of unique values within itself as compared to
58 /// the other vector which is provided as an input parameter, as defined by a
59 /// provided custom comparator.
60 ///
61 /// # Example
62 /// ```
63 /// use array_tool::vec::Uniq;
64 ///
65 /// vec![1,2,3,4,5,6].uniq_via( vec![1,2,5,7,9], |&l, r| l == r + 2 );
66 /// ```
67 ///
68 /// # Output
69 /// ```text
70 /// vec![1,2,4,6]
71 /// ```
72 fn uniq_via<F: Fn(&T, &T) -> bool>(&self, other: Self, f: F) -> Self;
73
74 /// `unique_via` removes duplicates, as defined by a provided custom comparator,
75 /// from within the vector and returns Self.
76 ///
77 /// # Example
78 /// ```
79 /// use array_tool::vec::Uniq;
80 ///
81 /// vec![1.0,2.0,1.4,3.3,2.1,3.5,4.6,5.2,6.2].unique_via( |l: &f64, r: &f64| l.floor() == r.floor() );
82 /// ```
83 ///
84 /// # Output
85 /// ```text
86 /// vec![1.0,2.0,3.3,4.6,5.2,6.2]
87 /// ```
88 fn unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> Self;
89
90 /// `is_unique_via` returns boolean value on whether all values within
91 /// Self are unique, as defined by a provided custom comparator.
92 ///
93 /// # Example
94 /// ```
95 /// use array_tool::vec::Uniq;
96 ///
97 /// vec![1.0,2.0,1.4,3.3,2.1,3.5,4.6,5.2,6.2].is_unique_via( |l: &f64, r: &f64| l.floor() == r.floor() );
98 /// ```
99 ///
100 /// # Output
101 /// ```text
102 /// false
103 /// ```
104 fn is_unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> bool;
105}
106
107impl<T: Clone + PartialEq> Uniq<T> for Vec<T> {
108 fn uniq(&self, other: Vec<T>) -> Vec<T> {
109 self.uniq_via(other, |lhs, rhs| lhs == rhs)
110 }
111 fn unique(&self) -> Vec<T> {
112 self.unique_via(|lhs, rhs| lhs == rhs)
113 }
114 fn is_unique(&self) -> bool {
115 self.is_unique_via(|lhs, rhs| lhs == rhs)
116 }
117
118 fn uniq_via<F: Fn(&T, &T) -> bool>(&self, other: Vec<T>, f: F) -> Vec<T> {
119 let mut out = self.unique();
120 for x in other.unique() {
121 for y in (0..out.len()).rev() {
122 if f(&x, &out[y]) {
123 out.remove(y);
124 }
125 }
126 }
127 out
128 }
129 fn unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> Vec<T> {
130 let mut a = self.clone();
131 for x in (0..a.len()).rev() {
132 for y in (x+1..a.len()).rev() {
133 if f(&a[x], &a[y]) {
134 a.remove(y);
135 }
136 }
137 }
138 a
139 }
140 fn is_unique_via<F: Fn(&T, &T) -> bool>(&self, f: F) -> bool {
141 let mut a = true;
142 for x in 0..self.len() {
143 for y in x+1..self.len() {
144 if f(&self[x], &self[y]) {
145 a = false;
146 break;
147 }
148 }
149 }
150 a
151 }
152}
153
154/// Removes, or Adds, the first element of self.
155pub trait Shift<T> {
156 /// Removes and returns the first item from the vector
157 ///
158 /// # Example
159 /// ```
160 /// use array_tool::vec::Shift;
161 ///
162 /// let mut x = vec![0,1,2,3];
163 /// assert_eq!(x.shift(), Some(0));
164 /// assert_eq!(x, vec![1,2,3]);
165 /// ```
166 fn shift(&mut self) -> Option<T>;
167 /// Insert item at the beginning of the vector. No return value.
168 ///
169 /// # Example
170 /// ```
171 /// use array_tool::vec::Shift;
172 ///
173 /// let mut x = vec![1,2,3];
174 /// x.unshift(0);
175 /// assert_eq!(x, vec![0,1,2,3]);
176 /// ```
177 fn unshift(&mut self, other: T);
178}
179impl<T: PartialEq> Shift<T> for Vec<T> {
180 fn shift(&mut self) -> Option<T> {
181 if self.len() == 0 { return None; }
182 Some(self.remove(0))
183 }
184 fn unshift(&mut self, other: T) {
185 &self.insert(0, other);
186 }
187}
188
189/// Set Intersection — Returns a new array containing elements common to the two arrays,
190/// excluding any duplicates. The order is preserved from the original array.
191pub trait Intersect<T> {
192 /// # Example
193 /// ```
194 /// use array_tool::vec::Intersect;
195 ///
196 /// vec![1,1,3,5].intersect(vec![1,2,3]);
197 /// ```
198 ///
199 /// # Output
200 /// ```text
201 /// vec![1,3]
202 /// ```
203 fn intersect(&self, Self) -> Self;
204 /// # Example
205 /// ```
206 /// # use std::ascii::AsciiExt;
207 /// use array_tool::vec::Intersect;
208 ///
209 /// vec!['a','a','c','e'].intersect_if(vec!['A','B','C'], |l, r| l.eq_ignore_ascii_case(r));
210 /// ```
211 ///
212 /// # Output
213 /// ```text
214 /// vec!['a','c']
215 /// ```
216 fn intersect_if<F: Fn(&T, &T) -> bool>(&self, Self, validator: F) -> Self;
217}
218impl<T: PartialEq + Clone> Intersect<T> for Vec<T> {
219 fn intersect(&self, other: Vec<T>) -> Vec<T> {
220 self.intersect_if(other, |l, r| l == r)
221 }
222 fn intersect_if<F: Fn(&T, &T) -> bool>(&self, other: Self, validator: F) -> Self {
223 let mut out = vec![];
224 let a = self.unique();
225 let length = other.len();
226 for x in a {
227 for y in 0..length {
228 if validator(&x, &other[y]) {
229 out.push(x);
230 break;
231 }
232 }
233 }
234 out
235 }
236}
237
238/// Join vector of ToString capable things to a String with given delimiter.
239pub trait Join {
240 /// # Example
241 /// ```
242 /// use array_tool::vec::Join;
243 ///
244 /// vec![1,2,3].join(",");
245 /// ```
246 ///
247 /// # Output
248 /// ```text
249 /// "1,2,3"
250 /// ```
251 fn join(&self, joiner: &'static str) -> String;
252}
253impl<T: ToString> Join for Vec<T> {
254 fn join(&self, joiner: &'static str) -> String {
255 let mut out = String::from("");
256 for x in 0..self.len() {
257 out.push_str(&self[x].to_string());
258 if x < self.len()-1 {
259 out.push_str(&joiner)
260 }
261 }
262 out
263 }
264}
265
266/// Expand and duplicate the vectors content `times` the integer given
267pub trait Times {
268 /// # Example
269 /// ```
270 /// use array_tool::vec::Times;
271 ///
272 /// vec![1,2,3].times(3);
273 /// ```
274 ///
275 /// # Output
276 /// ```text
277 /// vec![1,2,3,1,2,3,1,2,3]
278 /// ```
279 fn times(&self, qty: i32) -> Self;
280}
281impl<T: Clone> Times for Vec<T> {
282 fn times(&self, qty: i32) -> Vec<T> {
283 if self.is_empty() { return vec![] };
284 let mut out = vec![self[0].clone();self.len()*(qty as usize)];
285 let mut cycle = self.iter().cycle();
286 for x in 0..self.len()*(qty as usize) {
287 out[x] = cycle.next().unwrap().clone();
288 }
289 out
290 }
291}
292
293/// Create a `union` between two vectors.
294/// Returns a new vector by joining with other, excluding any duplicates and preserving
295/// the order from the original vector.
296pub trait Union {
297 /// # Example
298 /// ```
299 /// use array_tool::vec::Union;
300 ///
301 /// vec!["a","b","c"].union(vec!["c","d","a"]);
302 /// ```
303 ///
304 /// # Output
305 /// ```text
306 /// vec![ "a", "b", "c", "d" ]
307 /// ```
308 fn union(&self, other: Self) -> Self;
309}
310impl<T: PartialEq + Clone> Union for Vec<T> {
311 fn union(&self, other: Vec<T>) -> Vec<T> {
312 let mut stack = self.clone();
313 for x in other { // don't use append method as it's destructive
314 stack.push(x)
315 }
316 stack.unique()
317 }
318}