Convert an array of integers into an array of strings in Ruby? - ruby

I have an array:
int_array = [11,12]
I need to convert it into
str_array = ['11','12']
I'm new to this technology

str_array = int_array.map(&:to_s)

str_array = int_array.collect{|i| i.to_s}

array.map(&:to_s) => array of integers into an array of strings
array.map(&:to_i) => array of strings into an array of integers

map and collect functions will work the same here.
int_array = [1, 2, 3]
str_array = int_array.map { |i| i.to_s }
=> str_array = ['1', '2', '3']
You can acheive this with one line:
array = [1, 2, 3]
array.map! { |i| i.to_s }
and you can use a really cool shortcut for proc: (https://stackoverflow.com/a/1961118/2257912)
array = [1, 2, 3]
array.map!(&:to_s)

Start up irb
irb(main):001:0> int_array = [11,12]
=> [11, 12]
irb(main):002:0> str_array = int_array.collect{|i| i.to_s}
=> ["11", "12"]
Your problem is probably somewhere else. Perhaps a scope confusion?

the shortest option:
int_array.map!(&:to_s)

Returns Int
x = [1,2,3,4,5,6,7,8,9,10] # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Returns String
y = 1,2,3,4,5 # => ["1", "2", "3", "4", "5"]

Related

Use of = vs .dup method

array = [1,2,3,4,5]
array1 = array
array2 = array.dup
puts array1 == array2
Why do we have a dup method when we can just assign to another variable?
array = [1,2,3,4,5]
array1 = array
array2 = array.dup
array << "aha"
p array1 # => [1, 2, 3, 4, 5, "aha"]
p array2 # => [1, 2, 3, 4, 5]
You're fooling yourself by:
Trying to reason from a single example.
Comparing the wrong things.
Array has its own == method that compares element by element so given:
a = [ 11 ]
b = [ 11 ]
then a == b is true even though a and b reference different arrays.
In general, = simply copies a reference similar to this in C:
int *i, *j;
i = j;
but dup makes a (shallow) copy.
If you compare the object_ids:
puts array1.object_id == array2.object_id
you'll see that the underlying array objects are different even though == says that the have equal contents.
A statement like:
array1 = array
just assigns a reference to array1 from array. This means that both array and array1 point to the same memory location. If you change the underlying array, it will be reflected in both copies:
irb(main):001:0> array = [1,2,3]
=> [1, 2, 3]
irb(main):002:0> array1 = array
=> [1, 2, 3]
irb(main):003:0> array
=> [1, 2, 3]
irb(main):004:0> array1
=> [1, 2, 3]
irb(main):005:0> array[0] = 10
=> 10
irb(main):006:0> array
=> [10, 2, 3]
irb(main):007:0> array1
=> [10, 2, 3]
If you use dup, it clones the underlying data, creating new, independent storage:
irb(main):008:0> array2 = array.dup
=> [10, 2, 3]
irb(main):009:0> array
=> [10, 2, 3]
irb(main):010:0> array2
=> [10, 2, 3]
irb(main):011:0> array2[0] = 20
=> 20
irb(main):012:0> array
=> [10, 2, 3]
irb(main):013:0> array2
=> [20, 2, 3]

Finding duplicates in nested arrays

I have a hash, which contains a hash, which contains a number of arrays, like this:
{ "bob" =>
{
"foo" => [1, 3, 5],
"bar" => [2, 4, 6]
},
"fred" =>
{
"foo" => [1, 7, 9],
"bar" => [8, 10, 12]
}
}
I would like to compare the arrays against the other arrays, and then alert me if they are duplicates. It is possible for hash["bob"]["foo"] and hash["fred"]["foo"] to have duplicates, but not for hash["bob"]["foo"] and hash["bob"]["bar"]. Same with hash["fred"].
I can't even figure out where to begin with this one. I suspect inject will be involved somewhere, but I could be wrong.
This snippet will return an array of duplicates for each key. Duplicates can only be generated for equal keys.
duplicates = (keys = h.values.map(&:keys).flatten.uniq).map do |key|
{key => h.values.map { |h| h[key] }.inject(&:&)}
end
This will return [{"foo"=>[1]}, {"bar"=>[]}] which indicates that the key foo was the only one containing a duplicate of 1.
The snippet above assume h is the variable name of your hash.
h = {
"bob" =>
{
"foo" => [1, 3, 5],
"bar" => [2, 4, 6]
},
"fred" =>
{
"foo" => [1, 7, 9],
"bar" => [1, 10, 12]
}
}
h.each do |k, v|
numbers = v.values.flatten
puts k if numbers.length > numbers.uniq.length
end
There are many ways to do it.
Here's one that should be easy to read.
It works in Ruby 1.9. It uses + to combine two arrays and then uses the uniq! operator to figure out whether there is a duplicate number.
h = { "bob" =>
{
"foo" => [1, 3, 5],
"bar" => [2, 4, 6]
},
"fred" =>
{
"foo" => [1, 7, 12],
"bar" => [8, 10, 12]
}
}
h.each do |person|
if (person[1]["foo"] + person[1]["bar"]).uniq! != nil
puts "Duplicate in #{person[1]}"
end
end
I'm not sure what exactly you are looking for. But at look at a possible solution, perhaps you can reuse something.
outer_hash.each do |person, inner_hash|
seen_arrays = Hash.new
inner_hash.each do |inner_key, array|
other = seen_arrays[array]
if other
raise "array #{person}/#{inner_key} is a duplicate of #{other}"
end
seen_arrays[array] = "#{person}/#{inner_key}"
end
end

Is there a particular function to retrieve then delete random array element?

I know I can do this in a couple of steps, but was wondering if there is a function which can achieve this.
I want to array#sample, then remove the element which was retrieved.
How about this:
array.delete_at(rand(array.length))
Another inefficient one, but super obvious what's going on:
array.shuffle.pop
What would be nice would be a destructive version of the sample method on Array itself, something like:
class Array
def sample!
delete_at rand length
end
end
Linuxios's has it perfect. Here is another example:
array = %w[A B C]
item_deleted = array.delete_at(1)
Here it is in irb:
1.9.2p0 :043 > array = %w[A B C]
=> ["A", "B", "C"]
1.9.2p0 :044 > item_deleted = array.delete_at(1)
=> "B"
1.9.2p0 :045 > array
=> ["A", "C"]
1.9.2p0 :047 > item_deleted
=> "B"
An alternative to the rand(array.length) approach already mentioned, could be this one
element = array.delete array.sample
Eksample:
>> array = (1..10).to_a
>> element = array.delete array.sample
>> array # => [1, 2, 4, 5, 6, 7, 8, 9, 10]
>> element # => 3
This is also a set of two operations, but at least you won't have to move away from the array itself.
If you need to sample a number of items and the remove those from the original array:
array = (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
grab = array.sample(4)
=> [2, 6, 10, 5]
grab.each{ |a| array.delete a }
=> [2, 6, 10, 5]
array
=> [1, 3, 4, 7, 8, 9]

Ruby: Building a hash from a string and two array values at a time

I'm trying to build a hash with:
hash = {}
strings = ["one", "two", "three"]
array = [1, 2, 3, 4, 5, 6]
so that I end up with:
hash = { "one" => [1, 2] ,
"two" => [3, 4] ,
"three" => [5, 6] }
I have tried:
strings.each do |string|
array.each_slice(2) do |numbers|
hash[string] = [numbers[0], numbers[1]]
end
end
But that yields:
hash = { "one" => [5,6] , "two" => [5,6], "three" => [5,6] }
I know why it does this (nested loops) but I don't know how to achieve what I'm looking for.
If you want a one-liner:
hash = Hash[strings.zip(array.each_slice(2))]
For example:
>> strings = ["one", "two", "three"]
>> array = [1, 2, 3, 4, 5, 6]
>> hash = Hash[strings.zip(array.each_slice(2))]
=> {"one"=>[1, 2], "two"=>[3, 4], "three"=>[5, 6]}
hash = {}
strings.each { |string| hash[string] = array.slice!(0..1) }
This is a solution using methods and techniques you seem familiar with. It is not a 'one liner' solution but if you are new might be more understandable for you. The first answer is very elegant though.
As Mu says, Zip method is the best choose:
Converts any arguments to arrays, then merges elements of self with corresponding elements from each argument. This generates a sequence of self.size n-element arrays, where n is one more that the count of arguments. If the size of any argument is less than enumObj.size, nil values are supplied. If a block is given, it is invoked for each output array, otherwise an array of arrays is returned.

How can I get a list from a Ruby enumerable?

I know of Python's list method that can consume all elements from a generator. Is there something like that available in Ruby?
I know of :
elements = []
enumerable.each {|i| elements << i}
I also know of the inject alternative. Is there some ready available method?
Enumerable#to_a
If you want to do some transformation on all the elements in your enumerable, the #collect (a.k.a. #map) method would be helpful:
elements = enumerable.collect { |item| item.to_s }
In this example, elements will contain all the elements that are in enumerable, but with each of them translated to a string. E.g.
enumerable = [1, 2, 3]
elements = enumerable.collect { |number| number.to_s }
In this case, elements would be ['1', '2', '3'].
Here is some output from irb illustrating the difference between each and collect:
irb(main):001:0> enumerable = [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> elements = enumerable.each { |number| number.to_s }
=> [1, 2, 3]
irb(main):003:0> elements
=> [1, 2, 3]
irb(main):004:0> elements = enumerable.collect { |number| number.to_s }
=> ["1", "2", "3"]
irb(main):005:0> elements
=> ["1", "2", "3"]

Resources