Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow only one of specific value in Ruby array

Tags:

ruby

What is the best way to allow only one of a specific value in an array?

For example, I would like to allow only one value of cat in the following array:

["dog", "cat", "cat", "hamster", "rabbit", "dog"]

such that it returned:

["dog", "cat", "hamster", "rabbit", "dog"]

EDIT: Apologies for not making this clear enough, I am not looking for uniq! I want to ensure that there is only 1 of a specified value.

like image 597
Paul Groves Avatar asked Oct 24 '25 03:10

Paul Groves


2 Answers

To make only one value unique:

a = ["dog", "cat", "cat", "hamster", "rabbit", "dog"]

(a.count("cat") - 1).times { a.delete_at(a.index("cat"))}

#=> ["dog", "cat", "hamster", "rabbit", "dog"]

This preserves the order of the elements in the array.

To delete consecutive items:

Use Enumerable#chunk:

a = ["dog", "cat", "cat", "hamster", "rabbit", "dog"]

a.chunk(&:itself).map(&:first)

#=> ["dog", "cat", "hamster", "rabbit", "dog"]

Note that in Ruby < 2.2 you have to use chunk{|w| w} because itself isn't defined.

like image 56
Mark Thomas Avatar answered Oct 25 '25 17:10

Mark Thomas


If you wish to modify the array in place:

def keep_one(arr, obj)
  i = arr.each_index.find { |i| arr[i] == obj }
  if i
    arr.delete(obj)
    arr.insert(i,obj)
  end
end

arr = ["dog", "cat", "cat", 7.2, { a: 3}, "cat", "dog"]

a = arr.dup
keep_one(a,"cat")
a #=> ["dog", "cat", 7.2, {:a=>3}, "dog"] 

a = arr.dup
keep_one(a,"dog")
a #=> ["dog", "cat", "cat", 7.2, {:a=>3}, "cat"] 

a = arr.dup
keep_one(a,7.2)
a #=> ["dog", "cat", "cat", 7.2, {:a=>3}, "cat", "dog"] 

a = arr.dup
keep_one(a,"pig")
a #=> ["dog", "cat", "cat", 7.2, {:a=>3}, "cat", "dog"] 

If you do not wish to modify arr:

keep_one(arr.dup,"cat")
  #=> ["dog", "cat", 7.2, {:a=>3}, "dog"] 
arr
  #=> ["dog", "cat", "cat", 7.2, {:a=>3}, "dog"] 

or

def keep_one(arr, obj)
  found = false
  arr.each_with_object([]) do |o,a|
    a << o unless o == obj && found
    found = true if o == obj
  end
end
like image 37
Cary Swoveland Avatar answered Oct 25 '25 17:10

Cary Swoveland