delete occurrences of extra elements in an array
18.11.2023 2 min readCreate a function that takes two arguments: an array
arr
and a numbernum
. If an element occurs inarr
more thannum
times, remove the extra occurrence(s) and return the result.
deleteOccurrences([1, 1, 1, 1], 2) ➞ [1, 1]
deleteOccurrences([13, true, 13, null], 1) ➞ [13, true, null]
deleteOccurrences([true, true, true], 3) ➞ [true, true, true]
Two solutions:
- Initialize a new array. For each element, we check if the array already contains
i
number of elements. If it does, we do nothing. If not, we append it to the array. - Deduplicate the original array, map over it and somehow find a way to repeat the elements
i
times, flattening it when we’re done.
Crystal:
def delete_occurrences(arr : Array(T), i : Int32) forall T
res = [] of T
arr.each { |el| res << el if res.count(el) < i }
res
end
def delete_occurrences_func(arr : Array(T), i : Int32) forall T
arr.uniq.flat_map { |el| Array.new(i, el) }
end
Nim:
func deleteOccurrences[T](s: seq[T], i: int): seq[T] =
for el in s:
if result.count(el) == i: continue
result.add(el)
func deleteOccurrencesFunc[T](s: seq[T], i: int): seq[T] =
let newS = collect(newSeq):
for el in s.deduplicate:
el.repeat(i)
return newS.foldl(a & b)
Found another use for collect
, which I’ve been using a lot more in recent days.
Raku:
sub delete-occurrences(@a, $i) {
my @n = [];
for @a -> $el {
@n.push($el) if @n.grep({$_ eqv $el}).elems < $i;
}
@n;
}
sub delete-occurrences-func(@a, $i) {
(do for @a.unique {$_ xx $i}.flat).Array;
}
ok delete-occurrences([13, True, 13, True], 1) == [13, True];
A gotcha: we cannot use smartmatching for the first solution when grepping! Any value that is truthy will evaluate to true, and that means we get a lot more elements than we want! Instead, we check that $_
is strictly eqv
to $el
.
Javascript:
function deleteOccurrences<T>(a: T[], i: number) {
const newA = [];
const map: Map<T, number> = new Map();
for (const el of a) {
const count = map.get(el) || 0;
if (count !== i) {
map.set(el, count + 1);
newA.push(el);
}
}
return newA;
}
function deleteOccurrencesFunc<T>(a: T[], i: number) {
const newA = [...new Set(a)];
return newA.flatMap((el) => new Array(i).fill(el));
}
Ugh… that first implementation is a lot longer than I would like. I don’t get why we don’t have count
yet in Javascript.
Built with Astro and Tailwind 🚀