How to remove a single value from an array in Ruby? - arrays

I want to remove the first instance of the lowest value in the array.
arr = [1,2,3,1,2,3]
arr.reject {|i| i == arr.min}
#=> [2,3,2,3]
But my code removes all instances of the lowest value in the array. I want a result such that:
[...]
#=> [2,3,1,2,3]
What's the most elegant solution to this problem?

On first blush, here are a couple of options:
arr.delete_at(arr.index(arr.min))
# or less readable but still valid
arr.delete_at arr.index arr.min
arr.delete_at(arr.each_with_index.min[1])
# or
arr.delete_at(arr.each_with_index.min.pop)
# or
arr.delete_at(arr.each_with_index.min.last)
The first is less code and more readable but makes two passes through the list instead of one. I have doubts as to whether any other construct will surpass option #1 in elegance, as ugly as it may (or may not?) be.
Note that both choices crash on an empty array. Here's a safer version:
arr.delete_at arr.index(arr.min) || 0

Just out of curiosity:
[1,2,3,1,2,3].tap { |a| a.delete_at a.each_with_index.min.last }
#⇒ [2, 3, 1, 2, 3]

You can use Enumerable#drop_while for this purpose
arr = [1,2,3,1,2,3]
arr.drop_while { |i| i == arr.min }
#=> [2, 3, 1, 2, 3]

Related

How to implement Ruby max_by to return all elements which have the maximum value?

Ruby max_by method finds the maximal element form an array. Sometimes the maximal elements are with multipicity, in this case max_by chooses only one of them, seemingly arbitrarily. When I need all of them, I use this approach currently, to find the maximal values in an array of arrays:
sorted=ary.sort_by{|a,b| b}.reverse
max_score=sorted.first[1]
t=sorted.take_while{|z| z[1]==max_score}
But how could I monkey-patch the Array class with a "maxes_by" method, which accept a block, similarly to max_by, and returns an array of the maximal values?
Without writing a new, optimized method that returns the expected output you can simply combine max_by and select:
maximum = array.max_by { |element| element[1] }
t = array.select { |element| element[1] == maximum[1] }
Another option might be to group all elements by the value in question (with group_by) and then just pick the list with the max value.
lists = array.group_by { |element| element[1] }
lists[lists.keys.maximum]
It's worth a mention that the task could be done in a single pass through the array, or more generally, in a single pass through any collection whose class includes Enumerable.
module Enumerable
def max_by_all
return each unless block_given?
last_yield = nil
each_with_object([]) do |e,a|
ye = yield(e)
case last_yield.nil? ? -1 : last_yield <=> ye
when -1
a.replace([e])
last_yield = ye
when 0
a << e
end
end
end
end
arr = [2, 4, 3, 4, 1, 2, 5, 3, 5, 1]
arr.max_by_all(&:itself)
#=> [5, 5]
arr = ["style", "assets", "misty", "assist", "corgi", "bossy", "bosses", "chess"]
arr.max_by_all { |s| s.count('s') }
#=> ["assets", "assist", "bosses"]
h = { a: 1, b: 3, c: 2, d: 3, e: 1 }
h.max_by_all(&:last)
#=> [[:b, 3], [:d, 3]]
arr = [1, 2, 3]
arr.max_by_all.map { |n| 2*n }
#=> [2, 4, 6]
In the last example max_by_all has no block and therefore returns an enumerator which merely enumerates the elements of self. This behaviour may seem pointless but I've provided for it (the line return each unless block_given?) to mimic the behaviour of Enumerable#max_by when no block is provided.
Using Monkey-Patch
class Array
def maxes_by
maximal = max_by { |x| yield(x) }
select { |x| yield(x) == yield(maximal) }
end
end
Usage
> ['house', 'car', 'mouse'].maxes_by { |x| x.length }
=> ['house', 'mouse']
But I don't recommend to monkey patch the Array class, this practice is dangerous and can potentially lead to undesirable effects on your system.
For our good, ruby language provides a nice feature to overcome this problem, the Refinements, which is a safe way for monkey patching on ruby.
To simplify, with the Refinements you can monkey patch the Array class and the changes will only be available inside the scope of the class that is using the refinement! :)
You can use the refinement inside the class you are working on and you are ready to go.
Using Refinements
module MaxesByRefinement
refine Array do
def maxes_by
maximal = max_by { |x| yield(x) }
select { |x| yield(x) == yield(maximal) }
end
end
end
class MyClass
using MaxesByRefinement
def test
a = %w(house car mouse)
a.maxes_by { |x| x.length } # maxes_by is available here!
end
end
Usage
> MyClass.new.test
=> ['house', 'mouse']

Ruby : Choosing between each, map, inject, each_with_index and each_with_object

When I started writing Ruby many years ago, it took me a while to understand the difference between each and map. It only got worse when I discovered all the other Enumerable and Array methods.
With the help of the official documentation and many StackOverflow questions, I slowly began to understand what those methods did.
Here is what took me even longer to understand though :
Why should I use one method or another?
Are there any guidelines?
I hope this question isn't a duplicate : I'm more interested in the "Why?" than the "What?" or "How?", and I think it could help Ruby newcomers.
A more tl;dr answer:
How to choose between each, map, inject, each_with_index and each_with_object?
Use #each when you want "generic" iteration and don't care about the result. Example - you have numbers, you want to print the absolute value of each individual number:
numbers.each { |number| puts number.abs }
Use #map when you want a new list, where each element is somehow formed by transforming the original elements. Example - you have numbers, you want to get their squares:
numbers.map { |number| number ** 2 }
Use #inject when you want to somehow reduce the entire list to one single value. Example - you have numbers, you want to get their sum:
numbers.inject(&:+)
Use #each_with_index in the same situation as #each, except you also want the index with each element:
numbers.each_with_index { |number, index| puts "Number #{number} is on #{index} position" }
Uses for #each_with_object are more limited. The most common case is if you need something similar to #inject, but want a new collection (as opposed to singular value), which is not a direct mapping of the original. Example - number histogram (frequencies):
numbers.each_with_object({}) { |number, histogram| histogram[number] = histogram[number].to_i.next }
Which object can I use?
First, the object you're working with should be an Array, a Hash, a Set, a Range or any other object that respond to each. If it doesn't, it might be converted to something that will. You cannot call each directly on a String for example, because you need to specify if you'd like to iterate over each byte, character or line.
"Hello World".respond_to?(:each)
#=> false
"Hello World".each_char.respond_to?(:each)
#=> true
I want to calculate something with each element, just like with a for loop in C or Java.
If you want to iterate over each element, do something with it and not modify the original object, you can use each. Please keep reading though, in order to know if you really should.
array = [1,2,3]
#NOTE: i is a bound variable, it could be replaced by anything else (x, n, element). It's a good idea to use a descriptive name if you can
array.each do |i|
puts "La"*i
end
#=> La
# LaLa
# LaLaLa
It is the most generic iteration method, and you could write any of the other mentioned methods with it. We will actually, for pedagogical purposes only. If you spot a similar pattern in your code, you could probably replace it with the corresponding method.
It is basically never wrong to use each, it is almost never the best choice though. It is verbose and not Ruby-ish.
Note that each returns the original object, but this is rarely (never?) used. The logic happens inside the block, and should not modify the original object.
The only time I use each is:
when no other method would do. The more I learn about Ruby, the less often it happens.
when I write a script for someone who doesn't know Ruby, has some programming experience (e.g. C, Fortran, VBA) and would like to understand my code.
I want to get an Array out of my String/Hash/Set/File/Range/ActiveRecord::Relation
Just call object.to_a.
(1..10).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
"Hello world".each_char.to_a
#=> ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
{:a => 1, :b => 2}.to_a
#=> [[:a, 1], [:b, 2]]
Movie.all.to_a #NOTE: Probably very inefficient. Try to keep an ActiveRecord::Relation as Relation for as long as possible.
#=> [Citizen Kane, Trois couleurs: Rouge, The Grapes of Wrath, ....
Some methods described below (e.g. compact, uniq) are only defined for Arrays.
I want to get a modified Array based on the original object.
If you want to get an Array based on the original object, you can use map. The returned object will have the same size as the original one.
array = [1,2,3]
new_array = array.map do |i|
i**2
end
new_array
#=> [1, 4, 9]
#NOTE: map is often used in conjunction with other methods. Here is the corresponding one-liner, without creating a new variable :
array.map{|i| i**2}
#=> [1, 4, 9]
# EACH-equivalent (For pedagogical purposes only):
new_array = []
array.each do |i|
new_array << i**2
end
new_array
#=> [1, 4, 9]
The returned Array will not replace the original object.
This method is very widely used. It should be the first one you learn after each.
collect is a synonym of map. Make sure to use only one of both in your projects.
I want to get a modified Hash based on the original Hash.
If your original object is a Hash, map will return an Array anyway. If you want a Hash back :
hash = {a: 1, b: 2}
hash.map{|key, value| [key, value*2]}.to_h
#=> {:a=>2, :b=>4}
# EACH-equivalent
hash = {a: 1, b: 2}
new_hash = {}
hash.each do |key,value|
new_hash[key]=value*2
end
new_hash
#=> {:a=>2, :b=>4}
I want to filter some elements.
I want to remove nil elements
You can call compact. It will return a new Array without the nil elements.
array = [1,2,nil,4,5]
#NOTE: array.map{|i| i*2} Would raise a NoMethodError
array.compact
# => [1, 2, 4, 5]
# EACH-equivalent
new_array = []
array.each do |integer_or_nil|
new_array << integer_or_nil unless integer_or_nil.nil?
end
new_array
I want to write some logic to determine if an element should be kept in the new Array
You can use select or reject.
integers = (1..10)
integers.select{|i| i.even?}
# => [2, 4, 6, 8, 10]
integers.reject{|i| i.odd?}
# => [2, 4, 6, 8, 10]
# EACH-equivalent
new_array = []
integers.each do |i|
new_array << i if i.even?
end
new_array
I want to remove duplicate elements from your Array
You can use uniq :
letters = %w(a b a b c)
letters.uniq
#=> ["a", "b", "c"]
# EACH-equivalent
uniq_letters = []
letters.each do |letter|
uniq_letters << letter unless uniq_letters.include?(letter)
end
uniq_letters
#TODO: Add find/detect/any?/all?/count
#TODO: Add group_by/sort/sort_by
I want to iterate over all the elements while counting from 0 to n-1
You can use each_with_index :
letters = %w(a b c)
letters.each_with_index do |letter, i|
puts "Letter ##{i} : #{letter}"
end
#=> Letter #0 : a
# Letter #1 : b
# Letter #2 : c
#NOTE: There's a nice Ruby syntax if you want to use each_with_index with a Hash
hash = {:a=>1, :b=>2}
hash.each_with_index{|(key,value),i| puts "#{i} : #{key}->#{value}"}
# => 0 : a->1
# 1 : b->2
# EACH-equivalent
i = 0
letters.each do |letter|
puts "Letter ##{i} : #{letter}"
i+=1
end
each_with_index returns the original object.
I want to iterate over all the elements while setting a variable during each iteration and using it in the next iteration.
You can use inject :
gauss = (1..100)
gauss.inject{|sum, i| sum+i}
#=> 5050
#NOTE: You can specify a starting value with gauss.inject(0){|sum, i| sum+i}
# EACH-equivalent
sum = 0
gauss.each do |i|
sum = sum + i
end
puts sum
It returns the variable as defined by the last iteration.
reduce is a synonym. As with map/collect, choose one keyword and keep it.
I want to iterate over all the elements while keeping a variable available to each iteration.
You can use each_with_object :
letter_ids = (1..26)
letter_ids.each_with_object({}){|i,alphabet| alphabet[("a".ord+i-1).chr]=i}
#=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6, "g"=>7, "h"=>8, "i"=>9, "j"=>10, "k"=>11, "l"=>12, "m"=>13, "n"=>14, "o"=>15, "p"=>16, "q"=>17, "r"=>18, "s"=>19, "t"=>20, "u"=>21, "v"=>22, "w"=>23, "x"=>24, "y"=>25, "z"=>26}
# EACH-equivalent
alphabet = {}
letter_ids.each do |i|
letter = ("a".ord+i-1).chr
alphabet[letter]=i
end
alphabet
It returns the variable as modified by the last iteration. Note that the order of the two block variables is reversed compared to inject.
If your variable is a Hash, you should probably prefer this method to inject, because h["a"]=1 returns 1, and it would require one more line in your inject block to return a Hash.
I want something that hasn't been mentioned yet.
Then it's probably okay to use each ;)
Notes :
It's a work in progress, and I would gladly appreciate any feedback. If it's interesting enough and fit in one page, I might extract a flowchart out of it.

How do I compare integer indexes in arrays when there are duplicate values?

First, some necessary background. I'm trying to make a number-based version of the game Mastermind as a way of learning to code in Ruby. My code basically works like this:
The computer generates an array (#computer_sequence) of 4 random numbers from 1-5
The user enters a 4 digit sequence, which winds up in an array called #user_array.
A method, called compare, iterates through #user_array, comparing the value and index of each number to those in #computer_sequence. The program then tells the user how many of their numbers have the correct value and the correct position, or how many numbers have the correct value only.
The problem: If there are multiple instances of a number in an array, they get the same index, right? Like if I have the array [1, 3, 3, 4], the number three has an index of 1, even though there are two 3s. For this program to work, though, each number has to have a unique position (is index even the word I want here?) in the array, even if the number occurs multiple times. Does that make sense?
Also, here's the code for the compare method:
def compare
value_only = 0
value_and_place = 0
puts "The computer's values are: #{#computer_sequence}"
puts "The user's values are: #{#user_array}"
#user_array.each do |candidate|
#computer_sequence.each do |computer_number|
if candidate == computer_number && #user_array.index(candidate) == #computer_sequence.index(computer_number)
value_and_place +=1
elsif candidate == computer_number && #user_array.index(candidate) != #computer_sequence.index(computer_number)
value_only +=1
end
end
end
Suppose
n = 4
computer = Array.new(n) { [1,2,3,4,5].sample }
#=> [3, 2, 3, 3]
user_digits = [2, 4, 2, 3]
First compute pairs of elements at the same index of computer and user_digits.
pairs = computer.zip(user_digits)
#=> [[3, 2], [2, 4], [3, 2], [3, 3]]
Compute number of values that match at the same position
pairs.count { |c,u| c==u }
#=> 1
Compute number of values that match at different positions
First remove the matches at the same positions of computer and user_digits.
comp, users = pairs.reject { |c,u| c==u }.transpose
#=> [[3, 2, 3], [2, 4, 2]]
meaning
comp #=> [3, 2, 3]
users #=> [2, 4, 2]
Now step through users removing the first matching element in comp (if there is one).
users.each do |n|
i = comp.index(n)
comp.delete_at(i) if i
end
So now:
comp #=> [3,3]
meaning that the number of elements that match at different positions is:
users.size-comp.size
#=> 1
Notice that we could alternatively compute the number of values that match at the same position as
n - users.size
For n equal to 4 this doesn’t offer any significant time saving, but it would if we had a problem with the same structure and n were large.
Alternative calculation
After computing
comp, users = pairs.reject { |c,u| c==u }.transpose
we could write
users.size - comp.difference(users).size
#=> 1
where Array#difference is as I defined it in my answer here.
Here
comp.difference(users)
#=> [3,3]
No, equal elements in an array don't have the same index. Maybe you're thinking that because Array#index only returns the index of the first element equal to its argument. But there are many ways to see that other equal elements have their own indexes. For example,
a = [1, 3, 3, 4]
a[1] == 3 # true
a[2] == 3 # also true
Aside from that issue, your algorithm doesn't quite match the rules of Mastermind. If there is one three in the computer's sequence and the player guesses two threes, both in different positions than the three in the computer's sequence, the player should be told that only one element of their sequence matches the computer's sequence in value but not position.
Given the above, plus that I think it would be clearer to calculate the two numbers separately, I'd do it like this:
value_and_place = 4.times { |i| #user_array[i] == #computer_sequence[i] }
value_only = (#user_array & #computer_sequence).length - value_and_place
That's less efficient than the approach you're taking, but CPU efficiency isn't important for 4-element arrays.
You can pass in the index value to your loop for each candidate using the each_with_index method. So when the first 3 is passed in, index will be 1 and when the second 3 is passed in, index will be 2.
The problem with using .index(candidate) is it returns the first index.
Try this:
#user_array.each_with_index do |candidate, index|
#computer_sequence.each do |computer_number|
if candidate == computer_number && candidate == #computer_sequence[index]
value_and_place +=1
elsif candidate == computer_number && candidate != #computer_sequence[index]
value_only +=1
end
end
end

How to find duplicates in array without using `uniq` method

I am doing a challenge to make a method that finds duplicate values in an array, and prints out a new array without the duplicates. Ruby has a built in uniq method; however, I am not allowed to use it.
In my mind, this should work:
def uniques(array)
tempPos = 0
arrayPos = 0
duplicate = true
result = [] # array the result will be "pushed" too
for arrayPos in 0..array.length
for tempPos in 0..array.length
# If the values at the indexes are the same. But the indexes are not the same.
# we have a duplicate
if array[arrayPos] == array[tempPos] && arrayPos != tempPos
duplicate = true
else
duplicate = false
end
if duplicate == false
result[arrayPos] = array[arrayPos]
end
end
puts duplicate
end
puts result.inspect
end
Output:
uniq *this is the short hand user input to run the method*
false
false
false
false
false
false
[1, 2, 1, 4, 5, nil]
I must be doing something wrong.
Are you allowed to use a Set?
require 'set'
array = [1, 2, 3, 3, 3, 4]
Set.new(array).to_a
#=> [1, 2, 3, 4]
An other way is to iterate over every pair in the array:
array.each_cons(2).with_object([array.first]) do |pair, result|
result << pair.last unless pair.first == pair.last
end
#=> [1, 2, 3, 4]
There are many ways to do that. Here's another. Suppose:
arr = [3,5,1,3,4,1,1]
Construct:
h = arr.group_by(&:itself)
#=> {3=>[3, 3], 5=>[5], 1=>[1, 1, 1], 4=>[4]}
The duplicates are given by:
h.select { |_,v| v.size > 1 }.keys
#=> [3, 1]
and an array without the duplicates is given by:
h.keys
#=> [3, 5, 1, 4]
Your logic works fine altough as mentioned above a set would work better. You could also sort the elements, and then find adjacent pairs that are the same value which wouldn't work as well as a set, but would have slightly better run-time than your current solution:
To polish what you currently have:
def uniques(array)
result = [] # array the result will be "pushed" too
for arrayPos in 0...array.length
duplicate = false
for tempPos in 0...result.length
# if the values at the indexes are the same... but the indexes are not the same...
# we have a duplicate
duplicate ||= (array[arrayPos] == result[tempPos])
end
if !duplicate
result << array[arrayPos]
end
end
puts result
end
an slightly better approach (altought still poor performance):
def uniques(array)
result = [] # array the result will be "pushed" too
for arrayPos in 0...array.length
duplicate = result.include?(array[arrayPos])
if !duplicate
result << array[arrayPos]
end
end
puts result
end
Although this solution is OK for a learning assignment, you should note that the complexity of this is O(n^2) (n-squared). What that means is that for an array of size n (for example n=10), you are doing n-squared (100) iterations.
It gets exponentially worse. If you have an array of length 1,000,000, you are doing 1,000,000,000,000 iterations. This is why using a set is so important, it's average run-time will be much lower.
A fairly simple way to so this is to leverage array.include?
new = []
arr.each { |x| new << x unless new.include?(x)}
puts new
That will give you an array (new) that only includes unique elements from the original array (arr)
Duplicate array easy way
arr1 = [1,3,4,5,6,6,6,1]
arry = Array.new(arr1)
puts arry
Find uniq array easy way using OR operator
arr1 = [1,3,4,5,6,6,6,1]
arr2 = Array.new # creating new array
arry = arr1 | arr2 # compare two array using OR operator
puts arry

Rules on Parenthesis for Block Variables

I ran across the following piece of code while reading The Ruby Way:
class Array
def invert
each_with_object({}).with_index { |(elem, hash), index| hash[elem] = index }
end
end
I want to make sure that I understand what the parenthesis are doing in (elem, hash).
The first method (each_with_object({})) will yield two objects to the block. The first object will be the element in the array; the second object will be the hash. The parentheses make sure that those two objects are assigned to different block variables. If I had instead used { |elem, index} #code }, then elem would be an array consisting of the element and the hash. I think that is clear.
My confusion lies with the fact that if I didn't chain these two methods, I would not have to use the parentheses, and instead could use: each_with_object({}) { |elem, obj #code }.
What are the rules about when parentheses are necessary in block variables? Why do they differ between the two examples here? My simplistic explanation is that, when the methods are not chained, then the yield code looks like yield (elem, obj), but when the methods are chained, the code looks like yield([elem, obj], index). (We can surmise that a second array would be passed in if we chained a third method). Is this correct? Is the object(s) passed in from the last chained method not an array?
I guess instead of all this conjecture, the question boils down to: "What does the yield statement look like when chaining methods that accept blocks?
Your question is only tangentially concerned with blocks and block variables. Rather, it concerns the rules for "disambiguating" arrays.
Let's consider your example:
[1,2,3].each_with_object({}).with_index {|(elem, hash), index| hash[elem] = index}
We have:
enum0 = [1,2,3].each_with_object({})
#=> #<Enumerator: [1, 2, 3]:each_with_object({})>
We can see this enumerator's elements by converting it to an array:
enum0.to_a
#=> [[1, {}], [2, {}], [3, {}]]
We next have:
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:each_with_object({})>:with_index>
enum1.to_a
#=> [[[1, {}], 0], [[2, {}], 1], [[3, {}], 2]]
You might want to think of enum1 as a "compound enumerator", but it's just an enumerator.
You see that enum1 has three elements. These elements are passed to the block by Enumerator#each. The first is:
enum1.first
#=> [[1, {}], 0]
If we had a single block variable, say a, then
a #=> [[1, {}], 0]
We could instead break this down in different ways using "disambiguation". For example, we could write:
a,b = [[1, {}], 0]
a #=> [1, {}]
b #=> 0
Now let's stab out all the elements:
a,b,c = [[1, {}], 0]
a #=> [1, {}]
b #=> 0
c #=> nil
Whoops! That's not what we wanted. We've just experienced the "ambiguous" in "disambiguate". We need to write this so that our intentions are unambiguous. We do that by adding parenthesis. By doing so, you are telling Ruby, "decompose the array in this position to its constituent elements". We have:
(a,b),c = [[1, {}], 0]
a #=> 1
b #=> {}
c #=> 0
Disambiguation can be extremely useful. Suppose, for example, a method returned the array:
[[1,[2,3],[[4,5],{a: 6}]],7]
and we wish to pull out all the individual values. We could do that as follows:
(a,(b,c),((d,e),f)),g = [[1,[2,3],[[4,5],{a: 6}]],7]
a #=> 1
b #=> 2
c #=> 3
d #=> 4
e #=> 5
f #=> {:a=>6}
g #=> 7
Again, you just have to remember that the parentheses simply mean "decompose the array in this position to its constituent elements".
The rule is basic: every enumerator has a “signature.” E.g. it yields two parameters, then the proc to be passed should expect two parameters to receive:
[1,2,3].each_with_index { |o, i| ...}
When the object might be expanded, like hash item, it may be expanded using parenthesis. Assuming, the iterator yields an array, [*arr]-like operation is permitted with.
The following example might shed a light on this:
[1,2,3].each_with_object('first') # yielding |e, obj|
.with_index # yielding |elem, idx|
# but wait! elem might be expanded here ⇑⇑⇑⇑
# |(e, obj), idx|
.each_with_object('second') do |((elem, fst_obj), snd_idx), trd_obj|
puts "e: #{elem}, 1o: #{fst_obj}, 2i: #{snd_idx}, 3o: #{trd_obj}"
end
#⇒ e: 1, 1o: first, 2i: 0, 3o: second
#⇒ e: 2, 1o: first, 2i: 1, 3o: second
#⇒ e: 3, 1o: first, 2i: 2, 3o: second

Resources