Count Fixnums in Ruby array - ruby

I have a function with an arbitrary number of arguments. My function looks like this:
sum(n, *rest)
How do I iterate through the array rest so that it will check if an argument is a Fixnum, sum it if it is, and do nothing otherwise? For example:
sum(5,1,2,k,D,3)
# => 6

Do as below :
ary = rest.grep(Fixnum)
# return the summation of the array elements, if array is not empty
# 0, when array is empty or contains only one element as `0`.
ary.reduce(0,:+)
Look #reduce and grep .
Examples :
ary = [1,"2",{1 => 2 },8]
ary.grep(Fixnum).inject(0,:+) # => 9
ary = ["2",{1 => 2 },(1..2)]
ary.grep(Fixnum).inject(0,:+) # => 0
# counting the how many Fixnums are there
ary = [1,"2",{1 => 2 },8]
ary.grep(Fixnum).size # => 2

Another way (though I prefer #Arup's use of grep):
a.group_by(&:class)[Fixnum].reduce(0,:+)
a = [1, :cat, 3, 'dog']
b = a.group_by(&:class) #=> {Fixnum=>[1,3],Symbol=>[:cat],String=>["dog"]}
c = b[Fixnum] #=> [1,3]
reduce(0,:+) #=> 4
I have assumed that zero is to be returned if the array contains no Fixnums. If, in that case, nil is to be returned, change reduce(0,:+) to reduce(:+).

Related

Is there a one liner or more efficient way to get this done?

Given a hash, for example:
hash = { "fish" => 2, "cat" => 3, "dog" => 1 }
I need to get:
A comma separated string for all the values, E.g. "2,3,1"
An integer that hold the total sum of the values, E.g. 6
My current code:
value_string = hash.map { |k,v| "#{v}"}.join(',')
sum = 0
hash.map { |k,v| sum += v}
You can do it like this:
hash.values.join(",") # => "2,3,1"
hash.values.inject(:+) # => 6
Here is a solution to compute both the values in single iteration (some sort of one liner)
r1,r2 = hash.reduce([nil, 0]){|m,(_,v)| [[m[0], v.to_s].compact.join(","),m[-1]+v]}
#=> ["2,3,1", 6]

Replace a single element in an array

I have an array with unique elements. Is there a way to replace a certain value in it with another value without using its index value?
Examples:
array = [1,2,3,4]
if array.include? 4
# "replace 4 with 'Z'"
end
array #=> [1,2,3,'Z']
hash = {"One" => [1,2,3,4]}
if hash["One"].include? 4
# "replace 4 with 'Z'"
end
hash #=> {"One" => [1,2,3,'Z']}
p array.map { |x| x == 4 ? 'Z' : x }
# => [1, 2, 3, 'Z']
You can do it as:
array[array.index(4)] = "Z"
If the element is not necessarily in the array, then
if i = array.index(4)
array[i] = "Z"
end
You can use Array#map
array = array.map do |e|
if e == 4
'Z'
else
e
end
end
to edit the array in place, rather than creating a new array, use Array#map!
If you have more than one thing you want to replace, you can use a hash to map old to new:
replacements = {
4 => 'Z',
5 => 'five',
}
array = array.map do |e|
replacements.fetch(e, e)
end
This make uses of a feature of Hash#fetch, where if the key is not found, the second argument is used as a default.
A very simple solution that assumes there will be no duplicates and that the order doesn't matter:
hash = { 'One' => [1, 2, 3, 4] }
hash['One'].instance_eval { push 'Z' if delete 4 }
instance_eval sets the value of self to the receiver (in this case, the array [1,2,3,4]) for the duration of the block passed to it.

How do I output the index of elements in an array that are also in another?

I have two arrays:
A = ["a","s","p","e","n"]
V = ["a","e","i","o","u"]
I want to output an array that shows the index of every element in array A that is also an element anywhere in V.
In other words:
some_function(A, V) == [0,3]
This is because A[0]="a" and A[3]="e" matches the elements "a" and "e" in array V. How do I do that?
Here is how I would do:
A = ["a","s","p","e","n"]
V = ["a","e","i","o","u"]
A.each_index.select{|i| V.include? A[i]} # => [0, 3]
If V is a Set of data (order doesn't matter, no duplicates), and it is large, then you might get a performance benefit by converting it to a Set so that the include? runs faster since Set is built on a hash and gets O(1) retrieval time:
require 'set'
A = ["a","s","p","e","n"]
V = Set.new ["a","e","i","o","u"]
A.each_index.select{|i| V.include? A[i]} # => [0, 3]
As #Arup has answered your question, I thought I might elaborate a bit. Arup suggested you do this:
A.each_index.select{|i| V.include? A[i]}
where
A = ["a","s","p","e","n"]
V = ["a","e","i","o","u"]
Firstly, what is A.each_index? Try it in IRB:
e = A.each_index # => #<Enumerator: ["a", "s", "p", "e", "n"]:each_index>
e.class # => Enumerator
e.to_a # => [0, 1, 2, 3, 4]
So the enumerator e is the receiver of the method Enumerable#select, Enumerable being a mix-in module that is included by several Ruby classes, including Enumerator. Want to check that?
e.respond_to?(:select) # => true
e.respond_to?(:map) # => true
e.respond_to?(:reduce) # => true
Next, note that A.each_index does not depend on the contents of A, just its size, so we could replace that with any enumerator that iterates from 0 to A.size - 1, such as:
m = A.size
m.times.select{|i| V.include? A[i]} # => [0, 3]
0.upto(m-1).select{|i| V.include? A[i]} # => [0, 3]
We can confirm these are Enumerator objects:
m.times.class # => Enumerator
0.upto(m-1).class # => Enumerator
The other main classes that include Enumerable are Array, Hash, Set, Range and IO (but, since Ruby 1.9, not String), so we could also do this:
Array(0...m).select{|i| V.include? A[i]} # => [0, 3]
(0...m).select{|i| V.include? A[i]} # => [0, 3]
require 'set'
Set.new(0..m-1).select{|i| V.include? A[i]} # => [0, 3]
Note that, regardless of the receiver's class, select returns an array. Most (but not all) Enumerable methods that return a collection, return an array, regardless of the receiver's class.

How to initialize an array in one step using Ruby?

I initialize an array this way:
array = Array.new
array << '1' << '2' << '3'
Is it possible to do that in one step? If so, how?
You can use an array literal:
array = [ '1', '2', '3' ]
You can also use a range:
array = ('1'..'3').to_a # parentheses are required
# or
array = *('1'..'3') # parentheses not required, but included for clarity
For arrays of whitespace-delimited strings, you can use Percent String syntax:
array = %w[ 1 2 3 ]
You can also pass a block to Array.new to determine what the value for each entry will be:
array = Array.new(3) { |i| (i+1).to_s }
Finally, although it doesn't produce the same array of three strings as the other answers above, note also that you can use enumerators in Ruby 1.8.7+ to create arrays; for example:
array = 1.step(17,3).to_a
#=> [1, 4, 7, 10, 13, 16]
Oneliner:
array = [] << 1 << 2 << 3 #this is for fixnums.
or
a = %w| 1 2 3 4 5 |
or
a = [*'1'..'3']
or
a = Array.new(3, '1')
or
a = Array[*'1'..'3']
Along with the above answers , you can do this too
=> [*'1'.."5"] #remember *
=> ["1", "2", "3", "4", "5"]
To prove There's More Than One Six Ways To Do It:
plus_1 = 1.method(:+)
Array.new(3, &plus_1) # => [1, 2, 3]
If 1.method(:+) wasn't possible, you could also do
plus_1 = Proc.new {|n| n + 1}
Array.new(3, &plus_1) # => [1, 2, 3]
Sure, it's overkill in this scenario, but if plus_1 was a really long expression, you might want to put it on a separate line from the array creation.
You can do
array = ['1', '2', '3']
As others have noted, you can also initialize an array with %w notation like so:
array = %w(1 2 3)
or
array = %w[1 2 3]
Please note that in both cases each element is a string, rather than an integer.
So if you want an array whose elements are integers, you should not wrap each element with apostrophes:
array_of_integers = [1, 2, 3]
Also, you don't need to put comma in between the elements (which is necessary when creating an array without this %w notation). If you do this (which I often did by mistake), as in:
wrong_array = %w(1, 2, 3)
its elements will be three strings ---- "1,", "2,", "3". So if you do:
puts wrong_array
the output will be:
1,
2,
3
=>nil
which is not what we want here.
Hope this helps to clarify the point!
To create such an array you could do:
array = ['1', '2', '3']
If you have an Array of strings, you can also initialize it like this:
array = %w{1 2 3}
just separate each element with any whitespace
You can initialize an array in one step by writing the elements in [] like this:
array = ['1', '2', '3']
You can simply do this with %w notation in ruby arrays.
array = %w(1 2 3)
It will add the array values 1,2,3 to the arrayand print out the output as ["1", "2", "3"]

Distinct difference between collect and each? [duplicate]

This question already has answers here:
what's different between each and collect method in Ruby [duplicate]
(7 answers)
Closed 8 years ago.
Using arrays what's the main difference between collect and each? Preference?
some = []
some.collect do {|x| puts x}
some.each do |x|
puts x
end
array = [] is a shortcut to define an array object (long form: array = Array.new)
Array#collect (and Array#map) return a new array based on the code passed in the block. Array#each performs an operation (defined by the block) on each element of the array.
I would use collect like this:
array = [1, 2, 3]
array2 = array.collect {|val| val + 1}
array.inspect # => "[1, 2, 3]"
array2.inspect # => "[2, 3, 4]"
And each like this:
array = [1, 2, 3]
array.each {|val| puts val + 1 }
# >> 2
# >> 3
# >> 4
array.inspect # => "[1, 2, 3]"
Hope this helps...
collect (or map) will "save" the return values of the do block in a new array and return it, example:
some = [1,2,3,10]
some_plus_one = some.collect {|x| x + 1}
# some_plus_one == [2,3,4,11]
each will only execute the do block for each item and wont save the return value.

Resources