How to intelligently split an array around an object

I have an array of indefinite length, say [1,2,3,4,5]. I want to subtract 1from everything that came before 3and add 1to everything after 3by making an example [0,1,3,5,6]. If not 3, add 1to everything: [1,2,4,5]=> [2,3,5,6]. What is the most elegant way to do this?

+3
source share
7 answers
a = [1, 2, 3, 4, 5]
n = a.index(3) || -1
a.map.with_index{|e, i| e + (i <=> n)}
# => [0, 1, 3, 5, 6]
+6
source

So, to get this on exactly one pass through the array, you need to start at the end by adding one to each element until you press 3, and then start subtracting it.

arr.reverse_each.slice_before(3).flat_map.with_index do |ar,i|
  ar.map do |x|  
    x += 1 if i == 0 unless x == 3    
    x -= 1 if i == 1    
    x
  end  
end.reverse

You can write the inner block much more succinctly, but I like it because this code is simple enough to read as is.

, - , ! (, @sawa, )

+1

Try something like this (Assume the array is sorted)

a = [1,2,3,4,5]
n = 3
a.include?(n) ? a.map {|e| e < n ? e-1 : e > n ? e + 1 : e } : a.map {|e| e + 1} 
# => [0, 1, 3, 5, 6]

It was a one-line syntax if you prefer ...

if a.include?(n)  
   a.map {|e| e < n ? e - 1 : e > n ? e + 1 : e }
else
   a.map {|e| e + 1}
end
0
source
if your_array.include?(3)    
  your_array.map do |item|
    if item > 3
      item + 1
    elsif item < 3
      item -1
    else
      item
    end
  end
else
  your_array.map{ |item| item + 1 }
end
0
source
def doit(a)
  n = a.include?(3) ? -1 : 1
  a.map { |i| (i==3 && n == -1) ? (n = 1; i) : i + n }
end

doit([1,2,3,4,5]) #=> [0, 1, 3, 5, 6] 
doit([6,5,4,2,1]) #=> [7, 6, 5, 3, 2]
doit([1,2,3,4,3]) #=> [0, 1, 3, 5, 4] 

I add one to three after the first, but if left unchanged, this is a simple fix.

0
source

I would do as below:

def add_sub(a)
  ind = a.index(3)|| -1
  a.each_index.map do |i|
    if ind < i
      a[i] + 1
    elsif ind > i
      a[i] - 1
    else
      a[i]
    end
  end
end

a1 = [1, 2, 3, 4, 5]
a2 = [1, 2, 7, 4, 5]

add_sub(a1) # => [0, 1, 3, 5, 6]
add_sub(a2) # => [2, 3, 8, 5, 6]
0
source

Use @sawa answer

If you want to manually go through the array, here you can make a direct path:

def trans_around(arr, elmt)
  ret = []

  found_at = -1 

  for i in 0...(arr.length) 
    if arr[i] == elmt
      found_at = i 
      break
    else
      ret << (arr[i] - 1)
    end
  end

  if (found_at > -1)
    ret << arr[found_at]

    for i in (found_at + 1)...(arr.length)
      ret << (arr[i] + 1)
    end
  else
    # rectify all the -1 we've done
    ret.each_with_index { |e,i| ret[i] += 2 }
  end

  return ret
end
0
source

All Articles