Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python list comprehension => Ruby select / reject on index rather than element

Tags:

arrays

ruby

Given:

arr=[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
      0   1   2   3   4   5   6   7   8    9    # index of arr

In Python, one can select or reject elements of a list given the index of that element by combining enumerate and an if clause in a list comprehension:

Every item except the third:

>>> [e for i,e in enumerate(arr) if i%3]
[20, 30, 50, 60, 80, 90]

Every third item in a list:

>>> [e for i,e in enumerate(arr) if not i%3]
[10, 40, 70, 100]

Or, even easier, with a slice:

>>> arr[::3]
[10, 40, 70, 100]   

In Ruby, we have .select and .reject

> arr.each_with_index.reject { |e,i| i%3==0 }
=> [[20, 1], [30, 2], [50, 4], [60, 5], [80, 7], [90, 8]]
> arr.each_with_index.select { |e,i| i%3==0 }
=> [[10, 0], [40, 3], [70, 6], [100, 9]]

And then apply .collect to that:

> arr.each_with_index.select { |e,i| i%3==0 }.collect{|e,i| e}
=> [10, 40, 70, 100]

For the slice, the rough Ruby equivalent might be:

> (0..arr.length).step(3).each { |e| p arr[e] }
10
40
70
100
=> 0..10

But I can't figure out how toe collect those into a new array other than:

> new_arr=[]
=> []
> (0..arr.length).step(3).each { |e| new_arr.push(arr[e]) }
=> 0..10
> new_arr
=> [10, 40, 70, 100]

Questions:

  1. Are these the best Ruby idioms for what I am trying to do (.select or .reject with .collect)?
  2. Is there a way to do something along these lines with a slice:
    new_arr=(0..arr.length).step(3).each { |e| arr[e] }.some_method?
like image 646
dawg Avatar asked Jul 03 '17 15:07

dawg


People also ask

How to select index elements from a list in Python?

my_list = [10, 11, 12, 13, 14] i = [1, 4] element = [] for index in i: element.append (my_list [index]) print (element) In this output, we can see that the specified index elements from the list are given and we will get the respective value in the new list. You can refer to the below screenshot Python select from the list.

Is there a list comprehension in Ruby similar to Python?

Since Ruby allows us to place the conditional after the expression, we get syntax similar to the Python version of the list comprehension.

What are some examples of list comprehensions in Python?

Below are some examples which depict the use of list comprehensions rather than the traditional approach to iterate through iterables: Example 1: Display square of numbers from 1 to 10. Example 2: Display even elements from a list of random numbers. Example 3: Toggle case of each character in a string.

How to select element from list with different probability using NumPy?

Python select element from list with different probability using NumPy To select elements from a Python list, we will use list.append (). We will create a list of indices to be accessed and the loop is used to iterate through this index list to access the specified element.


2 Answers

The method order is relevant:

arr.each_with_index.select { |e, i| i % 3 == 0 }
#=> [[10, 0], [40, 3], [70, 6], [100, 9]]

versus:

arr.select.each_with_index { |e, i| i % 3 == 0 }
#=> [10, 40, 70, 100]

Since select returns an enumerator, you could also use Enumerator#with_index:

arr.select.with_index { |e, i| i % 3 == 0 }
#=> [10, 40, 70, 100]

Regarding your slice equivalent, you can use map (or its alias collect) to collect the items in an array:

(0..arr.length).step(3).map { |e| arr[e] }
#=> [10, 40, 70, 100]

or values_at to fetch the items at the given indices:

arr.values_at(*(0..arr.length).step(3))
#=> [10, 40, 70, 100]

* turns the argument into an array (via to_a) and then into an argument list, i.e.:

arr.values_at(*(0..arr.length).step(3))
arr.values_at(*(0..arr.length).step(3).to_a)
arr.values_at(*[0, 3, 6, 9])
arr.values_at(0, 3, 6, 9)

Slightly shorter:

arr.values_at(*0.step(arr.size, 3))
#=> [10, 40, 70, 100]
like image 147
Stefan Avatar answered Oct 12 '22 23:10

Stefan


You could use each_slice to iterate over the arr and to get the elements "in threes", using each_slice(3):

p arr.each_slice(3).to_a
# => [[10, 20, 30], [40, 50, 60], [70, 80, 90], [100]]

So, having that array you can see that each first element is an element in the output you want to get, so you can use map and to get the first element:

arr = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
p arr.each_slice(3).map(&:first)
# => [10, 40, 70, 100]

You could do it as .map{|e| e.first}, or .map{|e| e[0]}, but for a shorter version you can use just .map(&:first).

like image 43
Sebastian Palma Avatar answered Oct 13 '22 01:10

Sebastian Palma