Map array values to the ruby hash key - ruby

here i have the sample code , mapping array to hash and appending hash to array but expected output is missing the array value
data = {"a"=>5,"b"=>["e","f"]}
data1 = [44,55]
s = []
data1.each_with_index do |i,index|
a = data1[index]
data["b"] = i
s << data
end
p s
output:
[{"a"=>5, "b"=>55}, {"a"=>5, "b"=>55}]
Expected output:
[{"a"=>5, "b"=>44}, {"a"=>5, "b"=>55}]

Your main problem is that you are putting the same object reference into each of your array elements. Think of it as putting two keys to the same locker in two different places. If you change the stuff in the locker, both keys will open it, and they will both see the same stuff. So, when you change the value of 'b', you change it for the object in both array elements, because they're the same object.
The solution is to start your block by creating a copy of the data object, changing its 'b' value, and putting the result into the resulting array.
I've also changed your each_with_index to map, because map is best to use when you are transforming the values in the array. Also, you don't need to have the index available in your block; you're just running through the array elements without caring which element you're working with while you're working with it.
data = {"a"=>5,"b"=>["e","f"]}
data1 = [44,55]
s = []
data1.map do |num|
the_copy = data.clone
the_copy['b'] = num
s << the_copy
end
p s

Related

Why isn't the following code working the way it should?

array = ["car","carrs"]
array.each { |x|
x.capitalize
}
I have tried doing with do too by removing the curly braces and adding do after .each, I have also tried for each in array, but that didnt work too. Am i doing something wrong because nothing gets capitalized?
String#capitalize returns a copy of the object with the first letter capitalized. What you're basically doing is looping through your array and generating new copies of the strings, but then immediately throwing them away.
You have a couple of ways to approach this:
You can use #map rather than #each to take each result of your loop block body and collect it into a new array:
array = ["car","carrs"]
capitalized_array = array.map { |x| x.capitalize }
Or, if you actually want to mutate the original strings, use String#capitalize! rather than capitalize, which mutates the input object, rather than returning a new object:
array = ["car","carrs"]
array.each { |x| x.capitalize! }
While it may seem tempting to use the mutative version, it is frequently a good idea to use non-mutative methods to produce transformations of your data, so you don't lose your original input data. Mutate-in-place can introduce subtle bugs by making the state of the data harder to reason about.
You have to understand the difference between map vs each. You can read it here.
For those who don't want to read that:
Each is like a more primitive version of map. It gives you every element so you can work with it, but it doesn’t collect the results. Each always returns the original, unchanged object. While map does the same thing, but. It returns a new array with the transformed elements.
So, you have to use map in order to return a new array:
array = ["car","carrs"]
capitalized_array = array.map { |x| x.capitalize }
# or
array = ["car","carrs"]
array.map! { |x| x.capitalize }
Now, what is the different between map and map!? We need to read the documentation
map invokes the given block once for each element of self. Creates a new array containing the values returned by the block. While map! invokes the given block once for each element of self, replacing the element with the value returned by the block.

Assign each value to array and access each element of the array individually

How would I assign values to a multidimensional array so that I can access each value by its index?
page = Nokogiri::HTML(open(url))
rows = page.css('table tr td')
times = rows.length - 16
rows[0..times].each { |row|
values = row.text.gsub(/\r\n?/, "").strip
#assign to array so I could access array[0] or array[6]
}
end
Also, is it possible to access the array outside of the .each block? It seems like the only thing I'm able to do is puts values before the closing }.
I'm very new to ruby, so I'm sorry for my ignorance.
Use map:
array = rows[0..times].map do |row|
row.text.gsub(/\r\n?/, "").strip
end
This builds a new array out of the return value from the block which is invoked on each element of your input array.
You could do as below using Enumerable#map:
Returns a new array with the results of running block once for every element in enum.
array = rows[0..times].map { |row| row.text.gsub(/\r\n?/, "").strip }

Delete one of many from Array

I have an Array that contains some elements multiple times. Now I want to create a new Array with one of those elements deleted.
Example:
a = [1,1,1,2]
delete_index = a.find_index(1)
result = a.clone
result.delete_at(delete_index)
# result is now [1,1,2]
This code looks really ugly for such an easy task. I had a look at the methods that Array provides, but couldn't find a better way of doing this.
a.delete_at(a.index(1) || a.length)
a.length handles the case where your element isn't found; because it's out of range, nothing will be deleted and your return value wil be nil.
If part of your question was to do this to a copy of the array, just call it on a clone:
a2 = a.clone ; a2.delete_at(...)
If you want to do this for each duplicated element, you can chain it to a block that selects the duplicated elements:
a.select { |e| array.count(e) > 1 }.each { |dup| a.delete_at a.index(dup) }
You could monkey patch Array:
class Array
def delete_first_occurrence(o)
delete_at(find_index(o) || length)
self
end
end
a = [1,1,1,2]
result = a.clone.delete_first_occurrence(1)
=> [1, 1, 2]
I can't quite tell, but it sounds like you're just trying to remove duplicates from the array. If that's the case, it's as easy as array.uniq, which will return a new array with all duplicates removed. If you'd like to modify the original array in place, you can use array.uniq! instead.
If that's not what you're trying to accomplish, please update your question with some example input and output of what you're trying to accomplish.

ruby: search an multi-dimensional array for a value and update if needed

Trying to look through an array and see if a particular value is set and if it is, update the numbers attached to it.
Example:
test = [['test',1,2],['watch',1,2],['fish',1,2]]
So I'd like to search this array for 'test' - if it exists, amend the values '1,2', if it doesn't exist, just add the new search term into the array.
New to ruby and having trouble searching inside a multi-dimensional array and getting the key back
I'd go for the hash method suggested in the comments, but if you're really wanting to store your data in the multidimensional array like that I suppose you could do something like:
search_term = "test"
search_item= nil
test.each do |item|
if item.include? search_term
search_item = item
end
end
if search_item.nil?
test << [search_term]
else
search_item << [1,2]
end
I think that would do it (although I'm a little fuzzy on what you were wanting to do after you found the item).

Array from a custom class in ruby

I have a custom class,
class Result
end
and i want to create an array of objects from it, but i cannot figure out how to do it? Because results = Array.new creates a new array, but i cannot find where to pass the class?
Presuming I understand the question correctly, the answer is: you don't. Ruby is dynamically typed, so the array is just an array and doesn't need to know that it's going to contain objects of class Result. You can put anything into the array.
Are you looking for something like this,
class Result
end
result = Array.new(5) { Result.new }
#=> [#<Result>, #<Result>, #<Result>, #<Result>, #<Result>]
Obviously you can pass any number you want.
results = Array.new creates an empty array (as would results = [], which is more succinct). To create an array containing result objects, either create an empty array and add elements to it, or use an array literal like [element1, element2, ...].
For example results = [Result.new, Result.new, Result.new] would create an array containing three Result objects.
You should just be able to create as many Result objects as you need and append them to the array. The array can hold objects of any type.
result1 = Result.new
result2 = Result.new
result3 = Result.new
results = Array.new
results << result1
results << result2
results << result3
Your results array now has 3 Result objects in it.

Resources