Remove duplicates from array in Ruby and perform an operation on a specific index
arr.each_with_object(Hash.new(0)) { |(*a,n),h| h[a] += n }.map(&:flatten)
#=> [["A", "Red", 15], ["B", "Red", 3], ["B", "Blue", 5], ["C", "Blue", 3],
# ["C", "Black", 1], ["D", nil, 9]]
The first step of the calculation is:
h = arr.each_with_object(Hash.new(0)) { |(*a,n),h| h[a] += n }
#=> {["A", "Red"]=>15, ["B", "Red"]=>3, ["B", "Blue"]=>5,
# ["C", "Blue"]=>3, ["C", "Black"]=>1, ["D", nil]=>9}
This uses the form of Hash::new that takes an argument called the default value. All that means is that when Ruby's parser expands h[a] += 1
to
h[a] = h[a] + n
h[a]
on the right returns h
's default value, 0
, if h
does not have a key a
. For example, when h
is empty,
h[["A", "Red"]] = h[["A", "Red"]] + 7 #=> 0 + 7 => 7
h[["A", "Red"]] = h[["A", "Red"]] + 8 #=> 7 + 8 => 15
h
does not have a key ["A", "Red"]
in the first expression, so h[["A", "Red"]]
on the right returns the default value, 0
, whereas h
does have that key in the second expression so the default value does not apply.
h.map(&:flatten)
is shorthand for
h.map { |a| a.flatten }
When the block variable a
is set equal to first key-value pair of h
,
a #=> [["A", "Red"], 15]
So
a.flatten
#=> ["A", "Red", 15]
To understand|(*a,n),h|
we need to construct the enumerator
enum = arr.each_with_object(Hash.new(0))
#=> #<Enumerator: [["A", "Red", 7], ["A", "Red", 8], ["B", "Red", 3],
# ["B", "Blue", 2], ["B", "Blue", 3], ["C", "Blue", 3],
# ["C", "Black", 1], ["D", nil, 4], ["D", nil, 5]]
# :each_with_object({})>
We now generate the first value from the enumerator (using Enumerator#next) and assign values to the block variables:
(*a,n),h = enum.next
#=> [["A", "Red", 7], {}]
a #=> ["A", "Red"]
n # => 7
h #=> {}
The way in which the array returned by enum.next
is broken up into constituent elements that are assigned to the block variables is called array decomposition. It is a powerful and highly useful techique.
Ruby - Merge two arrays and remove values that have duplicate
You can do the following!
# Merging
c = a + b
=> [1, 2, 3, 4, 5, 2, 4, 6]
# Removing the value of other array
# (a & b) is getting the common element from these two arrays
c - (a & b)
=> [1, 3, 5, 6]
Dmitri's comment is also same though I came up with my idea independently.
How can I remove duplicates in an array without using `uniq`?
the problem is that the inner loop is an infinite loop:
while true
sorted.delete_if {|i| i = i + count}
count += 1
end #while
you can probably do what you are doing but it's not eliminating duplicates.
one way to do this would be:
numbers = [1, 4, 2, 4, 3, 1, 5]
target = []
numbers.each {|x| target << x unless target.include?(x) }
puts target.inspect
to add it to the array class:
class ::Array
def my_uniq
target = []
self.each {|x| target << x unless target.include?(x) }
target
end
end
now you can do:
numbers = [1, 4, 2, 4, 3, 1, 5]
numbers.my_uniq
Ruby removing duplicates in enumerable lists
For array you can use uniq() method
a = [ "a", "a", "b", "b", "c" ]
a.uniq #=> ["a", "b", "c"]
so if you just
(1..10).to_a.uniq
or
%w{ant bat cat ant}.to_a.uniq
because anyway almost every methods you do implement will return as an Array class.
How to remove duplicate contiguous elements in an array?
I know you can do it with chunk_while
and map
, but there might be other ways:
[1,1,1,2,2,3,4,1,2].chunk_while { |e, f| e == f }.map(&:first)
# [1, 2, 3, 4, 1, 2]
With chunk_while
you split the array by chunks whenever the block is evaluated to true, for that the block yields two variables, the "element before" and the "element after", that's to say, for every iteration you're going to get this:
[1, 1]
[1, 1]
[1, 2]
[2, 2]
[2, 3]
[3, 4]
[4, 1]
[1, 2]
After applying the logic in the proc, it'll chunk the receiver whenever the first and second yielded elements are equal, and you get:
[[1, 1, 1], [2, 2], [3], [4], [1], [2]]
After that you can map that result to get only one element from each array - there are many ways, but first
is enough.
The chunk_while
proc can also be shortened to (&:==)
, leaving as [1,1,1,2,2,3,4,1,2].chunk_while(&:==).map(&:first)
.
Similarly and just out of curiosity, you can use slice_when
and last
to save 2 characters: [1,1,1,2,2,3,4,1,2].slice_when(&:!=).map(&:last)
.
Compare arrays and remove duplicates, in Ruby?
It's just set difference or subtraction and you can write it as such. Operator overloading can be a bliss :)
a
is what it is.
a
[[2, 1], [3, 3], [7, 2], [5, 6]]
b = b - a
[[6, 7], [9, 9], [4, 3]]
c = c - b - a # or c - (a + b)
[[1, 1], [2, 2]]
d = d - c - b - a # or d - (a + b + c)
[[3, 1]]
2D array - How to remove duplicate values but keep the sub arrays separated
The most generic approach would be:
[[1,2,3,4], [2,3,4,5], [3,4,5,6], [4,5,6,7]].
each_with_object([]) { |a, acc| acc << a - acc.flatten }
#⇒ [[1, 2, 3, 4], [5], [6], [7]]
or
[[1,2,3,4], [2,3,4,5], [3,4,5,6], [4,5,6,7]].
reduce([]) { |acc, a| acc << a - acc.flatten }
#⇒ [[1, 2, 3, 4], [5], [6], [7]]
Related Topics
Activerecord Connection Warning. (Database Connections Will Not Be Closed Automatically)
How to Parse a Url and Extract the Required Substring
Http Library for Ruby with Https, Ssl Client Certificate and Keep-Alive Support
Convert a String of 0-F into a Byte Array in Ruby
Why am I Getting This Passenger Error Could Not Find Rake-0.9.2.2 in Any of the Sources
How to Stringize/Serialize Ruby Code
Error Installing SQLite3 Gem via Bundler
Rails Force Ssl Only on Specified Controllers
"Msvcrt-Ruby18.Dll Was Not Found" with Ruby
Rspec: Should Be (This or That)
What Does ["String"].Pack('H*') Mean
Prefer %W(...) to a Literal Array
Why a Module's Singleton Method Is Not Visible in Downstream Eigenclasses Where It Gets Mixed