How to select element and surrounding elements from array, preferring return array with selected element in middle?

时间:2016-08-31 17:19:13

标签: arrays ruby

Let initial_array = (1..10).to_a.

I need it to be dynamic on number selection, but for an example: I need to select the number 5, as well as two elements on either side. Ideally, this would return: [3,4,5,6,7].

I know I can use each_cons to return the desired array length, with surrounding numbers. However, to select the desired element, I'm currently using initial_array.each_cons(5).find {|ary| ary.include?(5)}.

This returns [1,2,3,4,5], rather than the desired [3,4,5,6,7].

Additionally, I would like the function to work on both ends of the spectrum, with the returned array always at length 5, unless initial_array.length < 5, at which point returned_array.length == intial_array.length.

Thus, initial_array.solution_method(1) returns [1,2,3,4,5],

initial_array.solution_method(10) returns [6,7,8,9,10],

[1,2,3,].solution_method(2) returns [1,2,3].

4 个答案:

答案 0 :(得分:2)

It's not a one liner but maybe easier to understand?

input = (1..10)

def select_range(array, num, range)
  index = array.index(num) # find the value
  return [] if !index # return if the array doesn't include it

  array[(index - range)..(index + range)] # return the range of elements
end

p select_range(input.to_a, 5, 2)

output:

[3, 4, 5, 6, 7]

答案 1 :(得分:2)

def grab_part(arr, nbr, option=:avg)
  return nil unless (1..arr.size).include?(nbr)
  return nil if option!=:avg && !(nbr-1...arr.size).include?(option)
  first = (option==:avg) ? (arr.size-nbr)/2 : option-nbr+1
  arr[first,nbr]
end

nbr is the size of the array to be returned. option==:avg if the "middle" of arr is to be returned; else option is an index into arr identifying the last element of the array to be returned.

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

grab_part(arr,5)   #=> [3, 4, 5, 6, 7]
grab_part(arr,5,9) #=> [6, 7, 8, 9, 10]
grab_part(arr,5,4) #=> [1, 2, 3, 4, 5]

The following shows returned values for other values of the second parameter of grab_part.

(1..arr.size).map do |n|
  next if n==5
  puts "grab_part(arr,#{n}) \#=> #{ grab_part(arr,n) }" 
  puts "grab_part(arr,#{n},#{arr.size-1}) \#=> #{grab_part(arr,n,arr.size-1)}"
  puts "grab_part(arr,#{n},#{n-1}) \#=> #{grab_part(arr,n,n-1)}\n"
end
grab_part(arr,1)    #=> [5]
grab_part(arr,1,9)  #=> [10]
grab_part(arr,1,0)  #=> [1]
grab_part(arr,2)    #=> [5, 6]
grab_part(arr,2,9)  #=> [9, 10]
grab_part(arr,2,1)  #=> [1, 2]
grab_part(arr,3)    #=> [4, 5, 6]
grab_part(arr,3,9)  #=> [8, 9, 10]
grab_part(arr,3,2)  #=> [1, 2, 3]
grab_part(arr,4)    #=> [4, 5, 6, 7]
grab_part(arr,4,9)  #=> [7, 8, 9, 10]
grab_part(arr,4,3)  #=> [1, 2, 3, 4]
grab_part(arr,6)    #=> [3, 4, 5, 6, 7, 8]
grab_part(arr,6,9)  #=> [5, 6, 7, 8, 9, 10]
grab_part(arr,6,5)  #=> [1, 2, 3, 4, 5, 6]
grab_part(arr,7)    #=> [2, 3, 4, 5, 6, 7, 8]
grab_part(arr,7,9)  #=> [4, 5, 6, 7, 8, 9, 10]
grab_part(arr,7,6)  #=> [1, 2, 3, 4, 5, 6, 7]
grab_part(arr,8)    #=> [2, 3, 4, 5, 6, 7, 8, 9]
grab_part(arr,8,9)  #=> [3, 4, 5, 6, 7, 8, 9, 10]
grab_part(arr,8,7)  #=> [1, 2, 3, 4, 5, 6, 7, 8]
grab_part(arr,9)    #=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
grab_part(arr,9,9)  #=> [2, 3, 4, 5, 6, 7, 8, 9, 10]
grab_part(arr,9,8)  #=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
grab_part(arr,10)   #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
grab_part(arr,10,9) #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

A few more.

grab_part(arr,5,6)  #=> [5, 6, 7, 8, 9]
  #=> [3, 4, 5, 6, 7] 
grab_part(arr,5,8)  #=> [3, 4, 5, 6, 7] 
  #=> [5, 6, 7, 8, 9] 
grab_part(arr,5,3)  #=> [5, 6, 7, 8, 9] 
  #=> nil 
grab_part(arr,5,10) #=> [3, 4, 5, 6, 7] 
  #=> nil 

答案 2 :(得分:1)

To accomplish your task, you can use the slice method. Just fyi, (1..10) is a range object, not an array. To use the slice method, you need to change the range to an array first using (1..10).to_a

slice takes two inputs, starting index, and length. So you can do (1..10).to_a.slice(2,5) to get [3,4,5,6,7]

答案 3 :(得分:0)

这是我目前的工作解决方案。它并不像我想的那样雄辩,但它对我所寻找的东西有效。

def grab_neighbors(array, num, range)
  index = array.index(num)
  target_length = range * 2 + 1
  if index < range
    return array.slice(0, target_length)
  elsif index >= (array.length - range)
    return array.slice(-target_length, target_length)
  else
    return array[(index - range)..(index + range)]
  end
end