Remove elements from an array into another array (Ruby) - arrays

I'm new here and new to coding and I can use some help with a problem I'm trying to solve.
I'm trying to remove all integers that are less than 5 from array
a = [1, 2, 3, 4, 5, 6] and put them into a new array b = [], and then print out the b array.
I've done many Google searches but I can't find anything that helps.
I'm starting to think this is not possible.
Please help!
Thanks

a = [1, 2, 3, 4, 5, 6]
b, a = a.partition { |i| i < 5 }
#=> [[1, 2, 3, 4], [5, 6]]
b #=> [1, 2, 3, 4]
a #=> [5, 6]
See Enumerable#partition.

a = [1, 2, 3, 4, 5, 6]
b = a.select { |i| i < 5 } # [1, 2, 3, 4]
a = a - b # [5, 6]

To actually remove elements from a while putting them in an existing array b, you could use reject!:
a = [1, 2, 3, 4, 5, 6]
b = []
a.reject! { |i| b << i if i < 5 }
a #=> [5, 6]
b #=> [1, 2, 3, 4]
If i < 5 evaluates to true, b << i puts that element in b and returns a truthy result which causes reject! to remove it from a.
Likewise, if i < 5 evaluates to false, b << i is skipped, the block returns a falsy result and that element remains in a.

Related

Ruby - How do you perform an operation on each item of two (maybe more) arrays and populate them in a new array?

a = [6, 7, 8, 9, 10]
b = [1, 2, 3, 4, 5]
each of array a's items are divided by each of array b's items and put into a new array called c.
c = [6, 3, 2, 2, 2]
a = [6, 7, 8, 9, 10]
b = [1, 2, 3, 4, 5]
c = a.zip(b).map { |e| e.reduce :/ }
#⇒ [
# [0] 6,
# [1] 3,
# [2] 2,
# [3] 2,
# [4] 2
# ]
Array#zip zips the arrays together and then each element (array of 2 items zipped) is reduced with Integer#/.
I like mudasobwa's zip/map solution, but here are a couple alternatives:
a = [6, 7, 8, 9, 10]
b = [1, 2, 3, 4, 5]
c = Array.new(a.size) { |i| a[i] / b[i] }
c = a.map.with_index { |x, i| x / b[i] }
In particular, I might prefer the Array.new solution if the arrays aren't guaranteed to be the same length, because you can easily ensure you don't go over bounds:
c = Array.new([a.size, b.size].min) { |i| a[i] / b[i] }

Find most duplicated numbers inside a array

I have the following array
[1, 2, 3, 4, 5, 1, 2, 5, 3, 4, 2, 3, 1, 3, 2, 2]`
I want to find out 2 things:
1) How many duplicates of each number is it?
For instance: 1, 3 times, 4, 2 times etc.
2) Find 3 most duplicated numbers in the array.
For instance: [2, 3, 1] since 2 is duplicated 5 times, 3 is duplicated 4 times & 1 is duplicated 3 times.
I have tried
arr = [1, 2, 3, 4, 5, 1, 2, 5, 3, 4, 2, 3, 1, 3, 2, 2]
= arr.group_by { |e| e }.map { |e| e[0] if e[1][1] }.compact
But results are not what I am looking for: [1, 2, 3, 4, 5]
▶ arr.group_by { |e| e } # arr.group_by(&:itself) for Ruby >= 2.2
.map { |k, v| [k, v.count] } #⇒ [[1, 3], [2, 5], [3, 4], [4, 2], [5, 2]]
.sort_by { |(_, cnt)| -cnt } #⇒ [[2, 5], [3, 4], [1, 3], [4, 2], [5, 2]]
.take(3) #⇒ [[2, 5], [3, 4], [1, 3]]
.map(&:first)
#⇒ [2, 3, 1]
Remove three last clauses to get the whole unsorted result.
To get a count of duplicated entries per duplicate you can go with:
arr.group_by(&:itself)
.each_with_object({}) {|(k, v), hash| hash[k] = v.size }
#=> {1=>3, 2=>5, 3=>4, 4=>2, 5=>2}
To get 3 most duplicated entries:
arr.group_by(&:itself)
.sort_by { |_k, v| -v.size }
.take(3)
.map(&:first)
#=> [2, 3, 1]
1) How many duplicates of each number is it?
counts = Hash[arr.uniq.map{|_x| [_x, arr.count(_x)]}]
=> {1=>3, 2=>5, 3=>4, 4=>2, 5=>2}
2) Find 3 most duplicated numbers in the array
counts.sort_by { |a, b| -b }.take(3).map(&:first)
=> [2, 3, 1]
arr = [1, 2, 3, 4, 5, 1, 2, 5, 3, 4, 2, 3, 1, 3, 2, 2]
I suggest using a counting hash (see the reference to "default value" at Hash::new):
h = arr.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }
# => {1=>3, 2=>5, 3=>4, 4=>2, 5=>2}
and use the method Enumerable#max_by with an argument of 3 to obtain the three keys of h having the largest values:
h.max_by(3, &:last).map(&:first)
#=> [2, 3, 1]
Note that if h is largish, using max_by with an argument is more efficient that using Enumerable#sort_by or Array#sort and then discarding all but the three largest values. The Enumerable methods max_by, min_by max and min were changed to permit an argument (which defaults to 1) in Ruby v2.2.

Compare current element to the remaining in Array (Ruby)

I want to compare the current element inside an iteration to the rest of the elements in the array. I have no issues from the starting point. The issue comes when I am looking to compare the current element to the elements behind it inside the array.
array = [1, 2, 3, 2, 3, 4, 5]
array.each_with_index do |num, index|
break if array[index + 1] == nil
if num > array[index + 1]
puts "#{num} is greater than the #{array[index + 1]}!"
else
puts "#{num} is less than the #{array[index + 1]}!"
end
end
I am looking for something like:
"3 is greater than 1 and 2 but less than 4 and 5"
Any ideas?
I'm assuming you want all of the elements in the array compared, so you could do something like the following, by making use of Array#select:
array = [1, 2, 3, 2, 3, 4, 5]
filtered_array = array.uniq
array.each do |i|
greater_than = filtered_array.select { |comp| comp < i }
less_than = filtered_array.select { |comp| comp > i }
puts "#{i} is greater than #{greater_than} but less than #{less_than}"
end
You could play with formatting the output, but this would give:
1 is greater than [] but less than [2, 3, 4, 5]
2 is greater than [1] but less than [3, 4, 5]
3 is greater than [1, 2] but less than [4, 5]
2 is greater than [1] but less than [3, 4, 5]
3 is greater than [1, 2] but less than [4, 5]
4 is greater than [1, 2, 3] but less than [5]
5 is greater than [1, 2, 3, 4] but less than []
partition breaks divides up the elements into two separate groups.
array = [1,2,3,4,5]
array.each do |n|
less_than, greater_than = *(array - [n]).partition { |m| m <= n }
text = []
text << "is greater than #{less_than.join(', ')}" if less_than.count > 0
text << "is less than #{greater_than.join(', ')}" if greater_than.count > 0
puts "#{n} #{text.join(' and ')}"
end
arr = [1, 2, 3, 2, 3, 4, 5]
a = arr.uniq.sort
#=> [1, 2, 3, 4, 5]
h = a.each_with_index.to_h
#=> {1=>0, 2=>1, 3=>2, 4=>3, 5=>4}
arr.each { |i| puts "#{i} is greater than #{a[0,h[i]]} but less than #{a[h[i]+1..-1]}" }
prints
1 is greater than [] but less than [2, 3, 4, 5]
2 is greater than [1] but less than [3, 4, 5]
3 is greater than [1, 2] but less than [4, 5]
2 is greater than [1] but less than [3, 4, 5]
3 is greater than [1, 2] but less than [4, 5]
4 is greater than [1, 2, 3] but less than [5]
5 is greater than [1, 2, 3, 4] but less than []

Finding the first combination of two integers in an array whose latter element appears the earliest and sum matches a given value

I have array and sum_of_two:
array = [10, 5, 1, 9, 7, 8, 2, 4, 6, 9, 3, 2, 1, 4, 8, 7, 5]
sum_of_two = 10
I'm trying to find the combination of two integers in array whose latter element of the two appears the earliest among those of such combinations whose sum equals sum_of_two. For example, both [5, 5] and [1, 9] are candidates for such combinations, but 9 of [1, 9] (which appears later than 1 in array) appears earlier than the second 5 of [5, 5] (which is the last element in array). So I would like to return [1, 9].
I tried using combination and find:
array.combination(2).find{|x,y| x + y == sum_of_two} #=> [5, 5]
However, it returns a combination of the first integer in the array, 5 , and another integer further along the array, also 5.
If I use find_all instead of find, I get all combinations of two integers that add up to sum_of_two:
array.combination(2).find_all{|x,y| x + y == sum_of_two}
#=> [[5, 5], [1, 9], [1, 9], [9, 1], [7, 3], [8, 2], [8, 2], [2, 8], [4, 6], [6, 4], [9, 1], [3, 7], [2, 8]]
But then I'm not sure how to get the first one.
I would use Set (which would be a bit more efficient than using Array#include?) and do something like this:
array = [10, 5, 1, 9, 7, 8, 2, 4, 6, 9, 3, 2, 1, 4, 8, 7, 5]
sum_of_two = 10
require 'set'
array.each_with_object(Set.new) do |element, set|
if set.include?(sum_of_two - element)
break [sum_of_two - element, element]
else
set << element
end
end
#=> [1, 9]
x = array.find.with_index{|e, i| array.first(i).include?(sum_of_two - e)}
[sum_of_two - x, x] # => [1, 9]
Array#combination(n) does not give the elements in the order you want, so you must build the pairs yourself. It's easy if you begin from the second index. A O(n) lazy implementation, and let's call the input xs:
pairs = (1...xs.size).lazy.flat_map { |j| (0...j).lazy.map { |i| [xs[i], xs[j]] } }
first_matching_pair = pairs.detect { |i, j| i + j == 10 }
#=> [1, 9]

Divide array into subarray

I want to create two sub-arrays from this array:
a = [0, 1, 2, 3, 4, 5, 6]
This array will not always contain the same number of elements because it depends on the user input.
For example, in some occasions it'll be:
a = [0, 5]
or:
a = [5, 6, 4]
I want to divide the array into two subarrays. The first one will contain numbers from 1 to 4 (inclusive) and the second one will contain 0, 5 and 6.
In the first example, it will be:
a = [0, 1, 2, 3, 4, 5, 6]
sub_array1 = [1, 2, 3, 4]
sub_array2 = [0, 5, 6]
In the second:
a = [0, 5]
sub_array1 = []
sub_array2 = [5]
In the third:
a = [5, 6, 4]
sub_array1 = [4]
sub_array2 = [5, 6]
and so on, depending on the user input.
How can I do this?
First thing that comes to mind is Enumerable#partition.
sub_array1, sub_array2 = [0,1,2,3,4,5,6].partition {|x| (1..4).include? x }
=> [[1,2,3,4], [0,5,6]]
if you have two conditions (I mean if 0,5,6 are an actual condition and not the excluded set) I think that a double iteration wouldn't hurt
a = [0,1,2,3,4,5,6]
sub_array1 = a.select { |x| (1..4).include? x }
sub_array2 = a.select { |x| [0,5,6].include? x }
You can try something like this:
[0,1,2,3,4,5,6].group_by{|x| [0,5,6].include? x}
The result will be a hash:
{true=>[0, 5, 6], false=>[1, 2, 3, 4]}
In the second case:
[0,5].group_by{|x| [0,5,6].include? x}
The result will be:
{true=>[0, 5]}

Resources