Delete array element if next elements value overrides previous element value

21 views
Skip to first unread message

Roman Yarygin

unread,
Dec 23, 2014, 9:51:11 PM12/23/14
to rubyonra...@googlegroups.com
Hello! For example, I have array:

[["can", ":manage", ":site", nil],
["can", ":view", ":dashboard", nil],
["cannot", ":manage", ":site", nil]]

And I want to remove ["can", ":manage", ":site", nil] element, basing on
that ":manage" and ":site" elements are equal, but "cannot" element
appears later than "can". How can i achieve that?

--
Posted via http://www.ruby-forum.com/.

Dave Aronson

unread,
Dec 23, 2014, 10:01:44 PM12/23/14
to rubyonrails-talk
On Tue, Dec 23, 2014 at 9:50 PM, Roman Yarygin <li...@ruby-forum.com> wrote:

> Hello! For example, I have array:
>
> [["can", ":manage", ":site", nil],
> ["can", ":view", ":dashboard", nil],
> ["cannot", ":manage", ":site", nil]]
>
> And I want to remove ["can", ":manage", ":site", nil] element, basing on
> that ":manage" and ":site" elements are equal, but "cannot" element
> appears later than "can". How can i achieve that?

Use the middle two elements as a hash key.

-Dave

--
Dave Aronson, consulting software developer of Codosaur.us,
PullRequestRoulette.com, Blog.Codosaur.us, and Dare2XL.com.

Roman Yarygin

unread,
Dec 23, 2014, 10:55:48 PM12/23/14
to rubyonra...@googlegroups.com
Solved it like that:

abilities_array = []
roles.map(&:abilities).flatten(1).each do |e|
if i = abilities_array.find_index{|ar| ar[1]==e[1] && ar[2]==e[2]}
abilities_array[i] = e
else
abilities_array << e
end
end
abilities_array.map{|a| "#{a[0]} #{a[1]}, #{a[2]}#{", "+a[3] unless
a[3].blank?}"}

Dave Aronson

unread,
Dec 24, 2014, 10:28:45 AM12/24/14
to rubyonrails-talk
On Tue, Dec 23, 2014 at 10:54 PM, Roman Yarygin wrote:

> Solved it like that:
>
> abilities_array = []
> roles.map(&:abilities).flatten(1).each do |e|
> if i = abilities_array.find_index{|ar| ar[1]==e[1] && ar[2]==e[2]}
> abilities_array[i] = e
> else
> abilities_array << e
> end
> end
> abilities_array.map{|a| "#{a[0]} #{a[1]}, #{a[2]}#{", "+a[3] unless
> a[3].blank?}"}

I'm not even going to try to grok how that works. Using a temporary
hash as a filter is much simpler:

tmp_hash = {}
roles.map(&:abilities).each do |ability|
tmp_hash[ability[1,2]] = ability
end
abilities_array = tmp_hash.values

Or with tap:

abilities_array = {}.tap { |tmp_hash|
roles.map(&:abilities).each do |ability|
tmp_hash[ability[1,2]] = ability
end
}.values

(If you want *earlier* ones to take precedence, use ||= instead of =.)

Hashes are one of your bestest friends in the whole wide world. At
least, the world of Ruby. ;-) They're very fast, and extremely
useful.

Roman Yarygin

unread,
Dec 24, 2014, 6:32:36 PM12/24/14
to rubyonra...@googlegroups.com
tmp_hash = {}
roles.map(&:abilities).each do |ability|
tmp_hash[ability[1,2]] = ability
end
abilities_array = tmp_hash.values

Or with tap:

abilities_array = {}.tap { |tmp_hash|
roles.map(&:abilities).each do |ability|
tmp_hash[ability[1,2]] = ability
end
}.values


Thank you, it looks much better =)
Reply all
Reply to author
Forward
0 new messages