Create an array from a hash with each_with_index - ruby

I have an array:
arr = ["a", "b", "c"]
What I want to do is to create a Hash so that it looks like:
{1 => "a", 2 => "b", 3 => c}
I tried to do that:
Hash[arr.each_with_index.map { |item, i| [i => item] }]
but didn't get what I was looking for.

each_with_index returns the original receiver. In order to get something different from the original receiver, map is necessary anyway. So there is no need of an extra step using each or each_with_index. Also, with_index optionally takes the initial index.
Hash[arr.map.with_index(1){|item, i| [i, item]}]
# => {1 => "a", 2 => "b", 3 => c}

Hash[] takes an array of arrays as argument. So you need to use [i, item] instead of [i => item]
arr = ["a", "b", "c"]
Hash[arr.each_with_index.map{|item, i| [i+1, item] }]
#=> {1=>"a", 2=>"b", 3=>"c"}
Just for clarification: [i => item] is the same as writing [{i => item}] so you really produced an array of arrays that in turn contained a single hash each.
I also added a +1 to the index so the hash keys start at 1 as you requested. If you don't care or if you want to start at 0, just leave that off.

arr = ["a", "b", "c"]
p Hash[arr.map.with_index(1){|i,j| [j,i]}]
# >> {1=>"a", 2=>"b", 3=>"c"}

Related

How do I move an element of an array one place up/down with Ruby

Let's say I have this array
array = ['a', 'b', 'c', 'd']
What is a good way to target an element (for example 'b') and switch it with the next element in line (in this case 'c') so the outcome becomes:
=> ['a', 'c', 'b', 'd']
array[1], array[2] = array[2], array[1]
array #=> ["a", "c", "b", "d"]
or
array[1, 2] = array.values_at(2, 1)
array #=> ["a", "c", "b", "d"]
There is no build in function to do this. You can swap the values like so:
array = %w[a b c d]
array[1..2] = array[1..2].reverse
array #=> ["a", "c", "b", "d"]
You could add some helper methods to the core array class.
class Array
def move_up(index)
self[index, 2] = self[index, 2].reverse
self
end
def move_down(index)
move_up(index - 1)
end
end
Note: Keep in mind that this solution mutates the original array. You could also opt for a version that creates a new array. For this version you can call #dup (result = dup) than work with result instead of self.
References:
Array#[]
Array#[]=
Array#reverse
Object#dup
Try this for swapping
array[0],array[1] = array[1],array[0]
or in general
array[i],array[i+1] = array[i+1],array[i]
Assuming that you want to target the elements by their indices, a combination of insert and delete_at would work:
array = %w[a b c d]
array.insert(2, array.delete_at(1))
array
#=> ["a", "c", "b", "d"]

Inverting a hash value (that's an array) into new individual keys

I have the following:
lumpy_hash = { 1 => ["A", "B"] }
then if I invoke Hash#invert on this hash, I'd like to get:
lumpy_hash = {"A" => 1, "B" => 1}
I don't get that from using Hash#invert. Any ideas on doing this? I'm not sure if I should try Hash#map or Hash#invert.
There are many ways to do this. Here is one:
Hash[lumpy_hash.map { |k,v| v.product([k]) }.first]
#=> {"A"=>1, "B"=>1}
I don't think the method Hash#invert is useful here.
The steps:
enum = lumpy_hash.map
#=> #<Enumerator: {1=>["A", "B"]}:map>
k,v = enum.next
#=> [1, ["A", "B"]]
k #=> 1
v #=> ["A", "B"]
a = v.product([k])
#=> ["A", "B"].product([1])
#=> [["A", 1], ["B", 1]]
Hash[a]
#=> {"A"=>1, "B"=>1}
Here's another way that makes use of a hash's default value. This one is rather interesting:
key,value = lumpy_hash.to_a.first
#=> [1, ["A","B"]]
Hash.new { |h,k| h[k]=key }.tap { |h| h.values_at(*value) }
#=> {"A"=>1,"B"=>1}
Object#tap passes an empty hash to its block, assigning it to the block variable h. The block returns h after adding three key-value pairs, each having a value equal to the hash's default value. It adds the pairs merely by computing the values of keys the hash doesn't have!
Here's another, more pedestrian, method:
lumpy_hash.flat_map{|k,vs| vs.map{|v| {v => k}}}.reduce(&:merge)
=> {"A"=>1, "B"=>1}

How to print last elements of array

how do I print all elements of an array after the second element ex:
ARR=["a","b","c","d","f"]
I want to print c d f
ARR=["cat","dog","horse"]
I want to print horse
Thanks in advance
Just as easy as
p ARR[2..-1]
where 2 and -1 are indexes of an elements.
Use Array#[] with range or Array#drop
arr = ["a","b","c","d","f"]
arr[2..-1]
# => ["c", "d", "f"]
arr.drop(2)
# => ["c", "d", "f"]
arr = ["cat","dog","horse"]
arr[2..-1]
# => ["horse"]
arr.drop(2)
# => ["horse"]
Use Array#last method
arr.last(arr.size - 2)

Each_pair analog for array (zipping 2 arrays)

There is each_pair method allows getting pairs of hash on every loop iteration:
{ 1 => "a", 2 => "b" }.each_pair do |key, value|
# do something with #{key} and #{value}
end
How can index of current array element could be known on every loop iteration?
array.each do |element|
# what is element index in array?
end
There is a boring solution using some incrementing iterator. But that iterator
should be assigned before the loop and should be manually incremented on every
iteration. It's obviously boring.
It will be great if there is a some way to zip some array with 1.. array and
get array of tuples like ["b", "d", "e"] → [(1,"b"), (2,"d"), (3,"e")] and
than pattern matched each element of the pair in| |` statement.
So, finally, what I am looking for is some function f, that:
f(["a"]) do |index, element|
# index == 1, element == "a"
end
You can loop over an array and get the current index by using Enumerable::each_with_index
Correct me if I'm wrong, but I'm assuming that you want an array consisting of sub-arrays with the originall arrays index and value?
a= ["b", "d", "e"]
a.enum_with_index.map {|ind, val| [ind, val]
=> [[0, "b"], [1, "d"], [2, "e"]]

Weird multiplicator operator behavior in a two arrays to hash combination

I was looking for a way to convert two arrays into a single hash. I found something like this :
a1 = [1,2,3]
a2 = [?A, ?B, ?C]
Hash[*a1.zip(a2).flatten]
I thought that this syntax was a bit weird, because Hash[a1.zip a2] would do exactly the same. But more than that, I don't understand the need for the * operator.
I know that it turns objects into arrays, or something alike (but not in the same way [] does, apparently).
When I execute :
a = a1.zip(a2).flatten
=> [1, "A", 2, "B", 3, "C"]
a = *a1.zip(a).flatten
=> [1, "A", 2, "B", 3, "C"]
Nothing really happens, and for what I know of the * operator, this seems to be the normal behavior.
So, why does
Hash[*a1.zip(a2).flatten]
=> {1=>"A", 2=>"B", 3=>"C"}
Hash[a1.zip(a).flatten]
=> {}
Return different values, given that the parameters seem identical ?
I guess I must be missing something about the * operator.
Thanks.
When the * operator is used with arrays like that it is called the splat operator.
Think of it as an operator that removes the first level of brackets around an array. This is quite useful because you can turn arrays into argument lists:
def stuff(x, y, z)
end
a = [1, 2, 3]
stuff(*a) # x,y,z gets assigned 1,2,3
The same thing works with Hash[]. The [] operator on Hash accepts as arguments:
An argument list of key-value pairs:
Hash["a", 1, "b", 2] #=> { "a" => 1, "b" => 2 }
An array or array pairs representing key-values:
Hash[ [["a", 1], ["b", 2]] ] #=> { "a" => 1, "b" => 2 }
Hash[] not does NOT accept a plain flat array as arguments:
Hash[ ["a", 1, "b", 2] ] #=> {}
So with this in mind, plus our understanding what the splat operator does you can now see what is happening:
paired_array = a1.zip(a2)
=> [[1, "A"], [2, "B"], [3, "C"]]
plain_array = a1.zip(a2).flatten
=> [1, "A", 2, "B", 3, "C"]
# Per rule 2 above we know this works
Hash[paired_array]
=> {1=>"A", 2=>"B", 3=>"C"}
# This won't work
Hash[plain_array]
=> {}
# But if we turn the plain_array into an argument list,
# then we know per rule 1 above that this will work
Hash[*plain_array]
=> {1=>"A", 2=>"B", 3=>"C"}
Now then you might be wondering what the hey is happening when you do:
a = *plain_array
=> [1, "A", 2, "B", 3, "C"]
Since we know the splat operator effectively strips the brackets, we get this:
a = 1, "A", 2, "B", 3, "C"
...which funnily enough is valid Ruby code and just creates an array again.
You can read more fun stuff about the splat operator in the rubyspec test case for the splat operator.
I think there's a mistake in your example, it should be like this:
Hash[a1.zip(a2).flatten] #=> {}
Hash[*a1.zip(a2).flatten] #=> {1=>"A", 2=>"B", 3=>"C"}
The splat operator in the assign mode converts an array to multiple arguments:
duck, cow, pig = *["quack","mooh","oing"] #=> ["quack","mooh","oing"]
Actually it's identical to
duck, cow, pig = ["quack","mooh","oing"] #=> ["quack","mooh","oing"]
But from the documentation you can see that Hash[...] receives multiple arguments, so the splat operator helps to assign each of those multiple arguments.
It's not that mysterious:
a1 = [1,2,3]
a2 = [?A, ?B, ?C]
p Hash[*a1.zip(a2).flatten] #{1=>"A", 2=>"B", 3=>"C"}
The * converts the array to a mere list (of arguments).
But why wasn't this syntax used?
p Hash[a1.zip(a2)]# {1=>"A", 2=>"B", 3=>"C"}
Well, it is new since Ruby 1.9.2. Your example is probably older.

Resources