Last active
August 29, 2015 13:55
-
-
Save jah2488/8689010 to your computer and use it in GitHub Desktop.
Non-destructively perform a difference operation on two arrays
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def diff(a,b) | |
hash_by_count(a) | |
.merge(hash_by_count(b)) { |_, av, bv| av - bv } | |
.flat_map { |k, v| [k] * v } | |
end | |
private | |
def hash_by_count(arr) | |
Hash[arr.group_by { |x| x }.map { |k, v| [k, v.count] }] | |
end | |
if $0 !~ /rspec/ | |
p diff([1,1,1], [1,1]) | |
p diff([1,2,1], [1,1]) | |
p diff([1,2,1], [2]) | |
p diff([1,2,1], [1]) | |
else | |
describe 'diff' do | |
it 'removes difference between arrs' do | |
expect(diff([1,1,1], [1,1])).to eq [1] | |
expect(diff([1,2,1], [1,1])).to eq [2] | |
expect(diff([1,2,1], [2])).to eq [1,1] | |
expect(diff([1,2,1], [1])).to eq [1,2] | |
end | |
it 'should work with non ints' do | |
expect(diff([:foo, :bar, :foo], [:foo])).to eq [:foo, :bar] | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Array | |
def -(other) | |
hash_by_count(self) | |
.merge(hash_by_count(other)) { |_, selfv, otherv| selfv - otherv } | |
.flat_map { |k, v| [k] * v } | |
end | |
private | |
def hash_by_count(arr) | |
Hash[arr.group_by { |x| x }.map { |k, v| [k, v.count] }] | |
end | |
end | |
[1,1,1] - [1,1] == [1] | |
[1,2,1] - [1] == [1,2] |
Someone was wondering what was going on with arr.group_by { |x| x }
and thats probably worth explaining a little. This is simply a way of telling ruby to group by self. This isn't normally very useful unless you are dealing with duplicates, where it will group them together into an array. This effect can be duplicated with group_by(&:to_s)
, but converts all your keys to strings in the process and doesn't work well if you want to preserve the original type.
[1, 2, 3, 4].group_by { |x| x }
#=> { 1=> [1], 2 => [2], 3 => [3], 4 => [4] }
[1, 2, 3, 4, 4].group_by { |x| x }
#=> { 1 => [1], 2 => [2], 3 => [3], 4=>[4, 4] }
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Requirements/Inspiration came from these tweets by https://twitter.com/coreyhaines/status/428289594035929088 and https://twitter.com/coreyhaines/status/428297286456578048
A more straightforward way of accomplishing this is with ruby's
delete_at
command, but my main goal in this was to try and avoid any destructive methods. So althoughb.each { |x| a.delete_at(a.index(x)) }
works and is very concise. I wanted to try and come up with a method that would not alter arraysa
andb
while also not sprayingdups
everywhere.