remove elements from array in ruby - ruby

I have an array and I want to remove some elements. I tried this but it doesn't work:
#restaurants.each_with_index do |restaurant, i|
if (restaurant.stars > 3) #restaurants.slice!(i) end
end
How can I do it?

#restaurants.reject!{|restaurant| restaurant.stars > 3}

You can use Array#delete_at(index): see rubydoc
But the best way for you will be to use reject! (rubydoc) or delete_if (rubydoc).

If restaurants is an array you can use pop, e.g.
a = [ "a", "b", "c", "d" ]
a.pop #=> "d"
a.pop(2) #=> ["b", "c"]
a #=> ["a"]

#restaurants.reject! {|restaurant| restaurant.stars > 3}

Related

using each_slice and sort Ruby

I need to reorganize an array into slices of 2 elements and then sort each slice alphabetically using each_slice
I've managed to get the each_slice correctly but I can seem to then sort each sub array.
What am I doing wrong here?
array.each_slice(2).to_a { |el| el = el.sort}
You just need to create a new array with the output that you want.
For instance:
# $ array = ["b", "a", "d", "c", "k", "l", "p"]
arr = []
array.each_slice(2) { |el| arr << el.sort}
# $ arr
# => [["a", "b"], ["c", "d"], ["k", "l"], ["p"]]
EDIT:
Pointed in the comments (by #mu is too short), you can also do:
arr = array.each_slice(2).map(&:sort)

How to extract each individual combination from a flat_map?

I'm fairly new to ruby and it's my first question here on stackoverflow so pardon me if I'm being a complete noob.
The code which i am working with contains this line -
puts (6..6).flat_map{|n| ('a'..'z').to_a.combination(n).map(&:join)}
What the code does is that its starts printing each of the combinations starting from "abcdef" and continues till the end (which i have never seen as it has 26^6 combinations).
Of course having an array of that size (26^6) is unimaginable hence I was wondering if there is any way by which i can get next combination in a variable, work with it, and then continue on to the next combination ?
For example I calculate the first combination as "abcdef" and store it in a variable 'combo' and use that variable somewhere and then the next combination is calculated and "abcdeg" is stored in 'combo' and hence the loop continues ?
Thanks
(6..6).flat_map { |n| ... } doesn't do much. Your code is equivalent to:
puts ('a'..'z').to_a.combination(6).map(&:join)
To process the values one by one, you can pass a block to combination:
('a'..'z').to_a.combination(6) do |combo|
puts combo.join
end
If no block is given, combination returns an Enumerator that can be iterated by calling next:
enum = ('a'..'z').to_a.combination(6)
#=> #<Enumerator: ["a", "b", "c", ..., "w", "x", "y", "z"]:combination(6)>
enum.next
#=> ["a", "b", "c", "d", "e", "f"]
enum.next
#=> ["a", "b", "c", "d", "e", "g"]
enum.next
#=> ["a", "b", "c", "d", "e", "h"]
Note that ('a'..'z').to_a.combination(6) will "only" yield 230,230 combinations:
('a'..'z').to_a.combination(6).size
#=> 230230
As opposed to 26 ^ 6 = 308,915,776. You are probably looking for repeated_permutation:
('a'..'z').to_a.repeated_permutation(6).size
#=> 308915776
Another way to iterate from "aaaaaa" to "zzzzzz" is a simple range:
('aaaaaa'..'zzzzzz').each do |combo|
puts combo
end
Or manually by calling String#succ: (this is what Range#each does under the hood)
'aaaaaa'.succ #=> "aaaaab"
'aaaaab'.succ #=> "aaaaac"
'aaaaaz'.succ #=> "aaaaba"

How to use keep_if with string array

I'm trying to use keep_if in my Rails 5 app with Ruby 2.3.1.
a = ["a", "b", "c", "d" ]
b = ["b", "d"]
a.keep_if { |v| v=~ /["#{b}"]/ }
#=> ["b", "d"]
Real project:
a = ["apple", "banana", "orange"]
b = ["mangoes", "banana", "pear"]
a.keep_if { |v| v=~ /["#{b}"]/ }
#=> ["mangoes", "banana", "pear"]
What I expected:
#=> ["banana"]
I'm guessing some sort of regex to be used? How to get what I expected?
keep_if() deletes every element of self for which block evaluates to false. See Array#select!
If no block is given, an enumerator is returned instead.
#Cary Swoveland has mentioned in a comment that the following should work if you want to use keep_if():
a.keep_if { |v| b.include?(v) } #=> ["banana"]
The following would work if you wanted to use Array#select! instead for perhaps a different scenario:
c = a+b
c.select { |x| c.count(x) == 2 }.uniq #=> ["banana"]
# (use .uniq > 2 for values that appear more than once)

Delete contents of array based on a set of indexes

delete_at only takes a single index. What's a good way to achieve this using built-in methods?
Doesn't have to be a set, can be an array of indexes as well.
arr = ["a", "b", "c"]
set = Set.new [1, 2]
arr.delete_at set
# => arr = ["a"]
One-liner:
arr.delete_if.with_index { |_, index| set.include? index }
Re-open the Array class and add a new method for this.
class Array
def delete_at_multi(arr)
arr = arr.sort.reverse # delete highest indexes first.
arr.each do |i|
self.delete_at i
end
self
end
end
arr = ["a", "b", "c"]
set = [1, 2]
arr.delete_at_multi(set)
arr # => ["a"]
This could of course be written as a stand-alone method if you don't want to re-open the class. Making sure the indexes are in reverse order is very important, otherwise you change the position of elements later in the array that are supposed to be deleted.
Try this:
arr.reject { |item| set.include? arr.index(item) } # => [a]
It's a bit ugly, I think ;) Maybe someone suggest a better solution?
Functional approach:
class Array
def except_values_at(*indexes)
([-1] + indexes + [self.size]).sort.each_cons(2).flat_map do |idx1, idx2|
self[idx1+1...idx2] || []
end
end
end
>> ["a", "b", "c", "d", "e"].except_values_at(1, 3)
=> ["a", "c", "e"]

delete array elements by certain criteria

What's the best and way to do this:
I have two arrays:
a=[['a','one'],['b','two'],['c','three'],['d','four']]
and b=['two','three']
I want to delete nested arrays inside a that include elements in b,to get this:
[['a','one']['d','four']
Thanks.
a = [['a','one'],['b','two'],['c','three'],['d','four']]
b = ['two','three']
a.delete_if { |x| b.include?(x.last) }
p a
# => [["a", "one"], ["d", "four"]]
rassoc to the rescue!
b.each {|el| a.delete(a.rassoc(el)) }
a=[['a','one'],['b','two'],['c','three'],['d','four']]
b=['two','three']
result=a.reject { |e| b.include?(e.first) or b.include?(e.last) }
# result => [["a", "one"], ["d", "four"]]

Resources