Ruby: concat fields from a hash based on specified order? - ruby-on-rails

data = {"B"=>"bb", "C"=>"cc", "A"=>"aa", "D"=>"dd", "E"=>"", "F"=>nil}
fields_to_select = ["A", "B", "C"]
str = data.select { |elem| fields_to_select.include? elem }.values.compact.reject(&:empty?).join(', ')
This would currently return bb, cc, aa since that is the order it's in the data hash.
Is there anyway way to create the string based on the order in fields_to_select?
So that it returns aa, bb, cc

Yes...possible using Hash#values_at
data = {"B"=>"bb", "C"=>"cc", "A"=>"aa", "D"=>"dd", "E"=>"", "F"=>nil}
fields_to_select = ["A", "B", "C"]
data.values_at(*fields_to_select).join(', ')
# => "aa, bb, cc"

Granted, values_at is cool stuff, but this problem can also be solved by a garden-variety use of our very old friend map.
fields_to_select.map { |k| data[k] }.join(', ')

Related

Remove array elements at indices non destructively

Let's say you have something like this:
my_array = ['some_rather', 'long_named', 'array_element', 'entry']
I want to remove arbitrary entries by index from my_array without changing it and I want the filtered (i.e. array with indices removed) to be returned from my call. Furthermore, I want to avoid chaining 4 separate calls and write a block doing so.
Example:
filtered_array = my_array.drop_indices(1,3)
You could chain Enumerable's with_index onto Array's reject method to do what you want, though this might violate your desire to not chain separate method calls or write a block to do this:
my_array = ['some_rather', 'long_named', 'array_element', 'entry', 'long_named']
indices_to_remove = [1, 3]
filtered = my_array.reject.with_index { |_, index| indices_to_remove.include?(index) }
p filtered # => ["some_rather", "array_element", "long_named"]
p my_array # => ["some_rather", "long_named", "array_element", "entry", "long_named"]
If this isn't acceptable, the only other thing I can think of right now, to keep duplicate items (as noted in my comment to your solution), is to change from indices_to_remove to indices_to_keep:
my_array = ['some_rather', 'long_named', 'array_element', 'entry', 'long_named']
indices_to_remove = [1, 3]
indices_to_keep = [*(0...my_array.length)] - indices_to_remove
filtered = my_array.values_at(*indices_to_keep)
p filtered # => ["some_rather", "array_element", "long_named"]
p my_array # => ["some_rather", "long_named", "array_element", "entry", "long_named"]
For Arrays with duplicate Elements the best I know is:
array = [0,15,8,15,8]
indices_to_remove = [1,4]
res = array.reject.with_index{ |_,i| indices_to_remove.include?(i) }
returns
[0,8,15]
Additionally for arrays with unique entries such as a set of users
(using variable definitions from the question)
filtered_array = my_array - my_array.values_at(1,3)
Bonus, if your indices are inside an array themselves:
indices_to_remove = [1,3]
filtered_array = my_array - my_array.values_at(*indices_to_remove)
I think this is rather descriptive, not awkward and not shorter than needed.
One more possible solution with some addition, now it's also will work with negative indexes:
array = %w( a b c d e f )
indexes = [1, 2, -1, -9, -6, 6]
def array_except(array, *indexes)
indexes = indexes.map { |e| e.negative? ? e + array.length : e }
array.values_at(*((0...array.length).to_a - indexes))
end
array_except(array, *indexes)
=> ["d", "e"]
array_except(array, 0, -1)
=> ["b", "c", "d", "e"]

Array iteration in rails controller: it only puts the last value

I have to iterate on array in my rails controller but it only returns the last value of it:
array = ["a", "b", "c"]
array.each do |arr|
#arry = arr
end
#arry gives me "c" but I want it to give me a b c
So, when I add a API method in the each iteration, it only gives me a result for the "c" value but I want a result for all of them.
FYI: when I iterate this array in my view, everything works
array.each do |el|
#arr = el
end
Every loop you are saving el as #arr (overriding previous value)so after full each you have last el. You can do it like this if you want to do something with each element.
#arr = array.map { |el| el }
or just
#arr = array
Use map enumerator:
#arry = array.map { |arr| arr }
https://ruby-doc.org/core-2.2.0/Array.html#method-i-map

Ruby find combination

I am trying to take input as a string.
Then I need to find all the possible combination and distinct combination but I am unable to do so.
input = "aabb"
Output I need to print all Combination =
'a','a','b','b','aa','ab','bb','aab','abb','aabb'
Now Distinct combination
'a','b','aa','ab','bb','aab','abb','aabb'
Then I need to count the letters and do a summation
'a','a','b','b','aa','ab','bb','aab','abb','aabb'
For this
result = 1+1+1+1+2+2+2+3+3+4
Similarly for the other combination I need to find summation.
You can use Array#combination.
To get all combinations:
input = "aabb"
res = []
input.size.times { |n| res << input.chars.combination(n+1).map { |a| a.join } }
res.flatten
#=> ["a", "a", "b", "b", "aa", "ab", "ab", "ab", "ab", "bb", "aab", "aab", "abb", "abb", "aabb"]
distinct combinations:
res.flatten.uniq
#=> ["a", "b", "aa", "ab", "bb", "aab", "abb", "aabb"]
to count the letters and do a summation:
res.flatten.uniq.map(&:size)
#=> [1, 1, 2, 2, 2, 3, 3, 4]
res.flatten.uniq.map(&:size).reduce(:+)
# => 18
To get all the substrings of your input (or more generally to get all subsequences of an Enumerable) you can use something like this:
def subsequences(e)
a = e.to_a
indices = (0..a.length - 1).to_a
indices.product(indices)
.reject { |i, j| i > j }
.map { |i, j| a[i..j] }
end
You would use that on your string like this: subsequences(input.chars).map(&:join). The chars and join are only necessary because Strings are not Enumerable, but the subsequences function does not really need that. You can just take out the first line and it should still work for strings (anything that has a "slicing" subscript operator, really ...).
Note also that this is not the only way to do this. The basic problem here is to iterate over all ordered pairs of indices of a sequence. You could also do that with basic loops. I just happen to find the cartesian product method very elegant. ;)
Once you have your first list in a variable, say list, the second task is as easy as list.uniq, and the third one is solved by
list.map(&:size).reduce(:+)

Get an array of the values of a key from an array of hashes?

For an array like this:
a = [{a:'a',b:'3'},{a:'b',b:'2'},{a:'c',b:'1'}]
I would like to return an array containing values for :a keys, so:
['a', 'b', 'c']
That can be done using:
a.map{|x|x[:a]}
I wonder if there is a native method in Rails or Ruby to do it like this?
a.something :a
You can do it yourself:
class Array
def get_values(key)
self.map{|x| x[key]}
end
end
Then you can do this:
a.get_values :a
#=> ["a", "b", "c"]
More than you need in this case, but from How to merge array of hashes to get hash of arrays of values you can get them all at once:
merged = a.inject{ |h1,h2| h1.merge(h2){ |_,v1,v2| [*v1,*v2] } }
p merged[:a] #=> ["a", "b", "c"]
p merged[:b] #=> ["3", "2", "1"]
Also, if you use something like Struct or OpenStruct for your values instead of hashes—or any object that allows you to get the "a" values as a method that does not require parameters—you can use the Symbol#to_proc convenience for your map:
AB = Struct.new(:a,:b)
all = [ AB.new('a','3'), AB.new('b','2'), AB.new('c','1') ]
#=> [#<AB a="a", b="3">, #<AB a="b", b="2">, #<AB a="c", b="1">]
all.map(&:a) #=> ["a", "b", "c"]
all.map(&:b) #=> ["3", "2", "1"]

Ruby array manipulation (Ruby 1.8 and Rails 2.2)

I'm hopelessly trying to write a method to manipulate an array in ruby. I'm trying to generate all in-order permutations of an array where each item is in turn replaced by an outside item. An example...
Given input:
arr = ["a", "b", "c"]
Desired output:
newArr = [ ["a", "b", "c"], ["a", "b", "*"], ["a", "*", "c"], ["a", "*", "*"], ["*", "b", "c"], ["*", "b", "*"], ["*", "*", "c"], ["*", "*", "*"] ]
Any help would be greatly appreciated. Thank you!
I don't understand your example order, either, but ignoring that, here's a solution in one line:
(0...(2**a.size)).map {|x| (0...a.size).map {|y| x & 2**y == 0 ? a[y] : val}}
I'm not sure permutation is the right word. If you count in binary, then you are replacing the things if there is a one. Here's that in Ruby:
def mike(arr, sub)
format = sprintf("%%0%db", arr.length)
m = Array.new
0.upto(2**arr.length-1) { |i|
bits = sprintf(format, i).split('')
a = Array.new
0.upto(arr.length-1) { |j|
if bits[j] == '0' then
a << arr[j]
else
a << sub
end
}
m[i] = a
}
return m
end
arr = ["a", "b", "c"]
p mike(arr, '*')
Is that if-then-else better with a ternary operator?
a <<= bits[j] == '0' ? arr[j] : sub
There must be a cleverer (or, at least more Rubyesque) way to do this, but it seems to produce the desired output.
ETA: Oops! My second and third items don't agree with yours. I guess I don't know what order you mean.
Similar to oylenshpeegui's method:
def toggle(arr, sub)
format = "%0#{arr.length}b"
(0...2**(arr.length)).to_a.map do |i|
sprintf(format,i).split('').zip(arr).map { |x| x[0] == "0" ? x[1] : sub }
end
end
The split/zip combo matches each digit of the binary expansion of the index with the element it is selecting. The map at the end uses the digit to decide if it should return the array element or the substitution.

Resources