iron_ingot/functions/
collections.rs

1use crate::any;
2
3use std::{
4  borrow::Cow,
5  cmp::Ordering::{Equal, Greater, Less},
6  collections::{HashMap, HashSet},
7  hash::Hash,
8};
9
10pub trait PropChecker {
11  /// It checks whether this object does not contain any duplicate elements.
12  fn is_unique(&self) -> bool;
13}
14
15impl<T: Eq + Hash> PropChecker for [T] {
16  fn is_unique(&self) -> bool {
17    let mut unique = HashSet::with_capacity(self.len());
18    self.iter().all(|value| unique.insert(value))
19  }
20}
21
22/// It find the minimum objects from the `slice` received determined by the value retrieved from each object in the
23/// `slice` through the `get_value` function given.
24///
25/// `slice`: The slice to be searched from.
26///
27/// `get_value`: The function that retrieves a value from the object in the `slice`.
28///
29/// It returns the minimum objects.
30pub fn min<T, R: Ord>(array: &[T], mut get_value: impl FnMut(&T, usize) -> R) -> Cow<[&T]> {
31  let mut min_value: Option<R> = None;
32  let mut result = vec![];
33  for (i, any) in array.iter().enumerate() {
34    let value = get_value(any, i);
35    if let Some(unwrapped_min_value) = &min_value {
36      match value.cmp(unwrapped_min_value) {
37        Greater => continue,
38        Less => {
39          min_value = Some(value);
40          result = vec![any];
41        }
42        Equal => result.push(any),
43      }
44    } else {
45      min_value = Some(value);
46      result = vec![any];
47    }
48  }
49  result.into()
50}
51
52/// It find the maximum objects from the `slice` received determined by the value retrieved from each object in the
53/// `slice` through the `get_value` function given.
54///
55/// `slice`: The array to be searched from.
56///
57/// `get_value: The function that retrieves a value from the object in the `slice`.
58///
59/// It returns the maximum objects.
60pub fn max<T, R: Ord>(array: &[T], mut get_value: impl FnMut(&T, usize) -> R) -> Cow<[&T]> {
61  let mut max_value: Option<R> = None;
62  let mut result = vec![];
63  for (i, any) in array.iter().enumerate() {
64    let value = get_value(any, i);
65    if let Some(unwrapped_max_value) = &max_value {
66      match value.cmp(unwrapped_max_value) {
67        Less => continue,
68        Greater => {
69          max_value = Some(value);
70          result = vec![any];
71        }
72        Equal => result.push(any),
73      }
74    } else {
75      max_value = Some(value);
76      result = vec![any];
77    }
78  }
79  result.into()
80}
81
82/// It converts the `map` given which may have duplicate objects into a slice without duplicates.
83///
84/// `map`: The map to be converted from.
85///
86/// It returns a slice without duplicates.
87pub fn into_slice<'a, K: Eq + Hash, V: crate::Hash<Part = &'a K>>(
88  map: HashMap<&'a K, &'a [&V]>,
89) -> Cow<'a, [&'a V]> {
90  let mut result = Vec::with_capacity(map.len());
91  let mut is_exists = HashMap::with_capacity(map.len());
92  for &anys in map.values() {
93    for &any in anys {
94      let hash = any.hash();
95      if is_exists.get(&hash).is_some() {
96        continue;
97      }
98      result.push(any);
99      is_exists.entry(hash).or_insert(true);
100    }
101  }
102  result.into()
103}
104
105/// It converts the `slice` given without duplicate objects into a map with duplicates.
106///
107/// `slice`: The slice to be converted from.
108///
109/// It returns a map with duplicates.
110pub fn into_map<'a, K: Eq + Hash, V: crate::Hash<Part = &'a K> + Eq + Hash>(
111  slice: &'a [&V],
112) -> HashMap<&'a K, Cow<'a, [&'a V]>> {
113  debug_assert!(
114    slice.is_unique(),
115    "slice must not contains duplicate objects!"
116  );
117  let mut result = HashMap::<_, Vec<_>>::new();
118  for &any in slice {
119    for &hash_part in &*any::hash::Hash::hash(any) {
120      result.entry(hash_part).or_insert(Vec::new()).push(any);
121    }
122  }
123  result
124    .into_iter()
125    .map(|(key, value)| (key, value.into()))
126    .collect()
127}
128
129/// It concatenates two maps received that may have duplicate objects into a map which contains duplicates.
130///
131/// `am`: The first map to include.
132///
133/// `bm`: The second map to include.
134///
135/// It returns a map which contains duplicates.
136pub fn add<'a, K: Eq + Hash, V: crate::Hash<Part = &'a K>>(
137  am: HashMap<&'a K, &'a [&V]>,
138  bm: HashMap<&'a K, &'a [&V]>,
139) -> HashMap<&'a K, Cow<'a, [&'a V]>> {
140  let mut rm = HashMap::<_, Vec<_>>::with_capacity(am.len() + bm.len());
141  let mut is_exists = HashMap::with_capacity(am.len());
142  for &a in into_slice(am).iter() {
143    let hash = a.hash();
144    for &hash_part in hash.iter() {
145      rm.entry(hash_part).or_insert(Vec::new()).push(a);
146    }
147    is_exists.entry(hash).or_insert(true);
148  }
149  for &b in into_slice(bm).iter() {
150    let hash = b.hash();
151    if is_exists.get(&hash).is_some() {
152      continue;
153    }
154    for &hash_part in hash.iter() {
155      rm.entry(hash_part).or_insert(Vec::new()).push(b);
156    }
157  }
158  rm.into_iter()
159    .map(|(key, value)| (key, value.into()))
160    .collect()
161}
162
163/// It removes objects from the first map where they exist in the second map and returns it.
164///
165/// `am`: The map to remove objects from.
166///
167/// `bm`: The map which contains the objects to be searched from the first map for removal.
168///
169/// It returns the first map without objects that exist in the second map.
170pub fn sub<'a, K: Eq + Hash, V: crate::Hash<Part = &'a K>>(
171  am: HashMap<&'a K, &'a [&V]>,
172  bm: HashMap<&'a K, &'a [&V]>,
173) -> HashMap<&'a K, Cow<'a, [&'a V]>> {
174  let mut rm = HashMap::<_, Vec<_>>::with_capacity(am.len());
175  let mut is_exists = HashMap::with_capacity(bm.len());
176  for &b in into_slice(bm).iter() {
177    is_exists.entry(b.hash()).or_insert(true);
178  }
179  for &a in into_slice(am).iter() {
180    let hash = a.hash();
181    if is_exists.get(&hash).is_some() {
182      continue;
183    }
184    for &hash_part in hash.iter() {
185      rm.entry(hash_part).or_insert(Vec::new()).push(a);
186    }
187  }
188  rm.into_iter()
189    .map(|(key, value)| (key, value.into()))
190    .collect()
191}