2

I have up to 7 integers representing each day of the week 0 ... 6 (sun - sat)

The current day = 3 (wednesday).

How can I reorder array of integers so that the number closest to Wednesday (3) comes first.

For example:

Current Day = 3
Days (input) = [0, 1, 2, 3, 4, 5, 6]
Correct Output = [3, 4, 5, 6, 0, 1, 2]

But the array may not contain all days (for example current day might be missing):

Current Day = 3
Days (input) = [0, 2, 4, 6]
Correct Output = [4, 6, 0, 2]

Basically reorder the array so that the current day comes first (or the integer that preceeds it)

Current Attempt: I've looked into using a.rotate but I'm unsure how to deal with if the current day is not in the array.

I've also tried using min_by but it does not loop integers

@days.min_by { |x| (x.to_f - Time.now.wday).abs } 
Onichan
  • 4,476
  • 6
  • 31
  • 60
  • See [here](http://stackoverflow.com/questions/1986386/check-if-a-value-exists-in-an-array-in-ruby). Use `.include?` to check if an array in Ruby contains a certain value – Arc676 Oct 23 '15 at 11:26
  • Could you define "closest to Wednesday"? Why does you second example's result start with `4` instead of `2`? – Stefan Oct 23 '15 at 11:49
  • @Stefan Sorry, I meant the closest day preceeding the current day. Basically, the next closest day in the week. – Onichan Oct 23 '15 at 12:00
  • Your current day, i.e. Wednesday (3) is preceded by Tuesday (2), not Thursday (4) – Stefan Oct 23 '15 at 12:13

3 Answers3

2

If you're looking for the days that come after the current day:

my_array.sort_by{|x| (x-current_day)%7}

If all you are looking for is the first number, simply use min_by instead of sort_by

And with your input:

irb(main):059:0* my_array = [0, 1, 2, 3, 4, 5, 6]
=> [0, 1, 2, 3, 4, 5, 6]
irb(main):060:0> current_day = 3
=> 3
irb(main):061:0> my_array.sort_by{|x| (x-current_day)%7}
=> [3, 4, 5, 6, 0, 1, 2]
irb(main):062:0> my_array = [0, 2, 4, 6]
=> [0, 2, 4, 6]
irb(main):063:0> my_array.sort_by{|x| (x-current_day)%7}
=> [4, 6, 0, 2]
davidrac
  • 10,723
  • 3
  • 39
  • 71
  • Quick question: how could I modify this so that it reorders the array so that the array always starts with the *next* day of the week and the current day is always the last. I've tried adding `+1` to the current day: `my_array.sort_by{|x| (x-current_day+1)%7}` but if the day is Saturday, the current day becomes `8` – Onichan Oct 23 '15 at 12:08
  • That's fine. the modulu operator will work correctly, just note that its minus 1 and not plus: `my_array.sort_by{|x| (x-current_day-1)%7}` – davidrac Oct 23 '15 at 12:13
  • Thanks. But I should be using `+1` to reorder the array starting with the next day right? Your comment uses `-1`. – Onichan Oct 23 '15 at 12:17
  • If you want the next day to be first then you should use `x-(current_day+1)`, which is like `x-current_day-1` (unless I'm missing something) – davidrac Oct 23 '15 at 12:18
1

All you need to do is find the index of the integer that preceeds input current day, if it itself is not included in the array. Here:

def mrotate(days, c_day)
  index = days.index(c_day)
  index = days.index(days.find { |d| d > c_day}) if !index
  days.rotate index || 0
end

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

mrotate([0, 2, 4, 6], 3)
#=> [4, 6, 0, 2]
shivam
  • 16,048
  • 3
  • 56
  • 71
  • on line `days.rotate index` i get the error: `no implicit conversion from nil to integer`. Even when days is a valid array such as: ` [0, 1, 2]` – Onichan Oct 23 '15 at 11:46
  • Consider `rotate while...`. What you have is more efficient than sorting, assuming that `days` is ordered, as it is in the example – Cary Swoveland Oct 23 '15 at 14:19
0

You can search for the first index that is >= 3 and split the array in two:

x = [0, 1, 2, 3, 4, 5, 6]
y = [0, 2, 4, 6]
pos = x.index{|s| s >= 3}
# => 3
x[pos..-1] + x[0..pos-1]
# [3, 4, 5, 6, 0, 1, 2]
pos = y.index{|s| s >= 3}
# => 2
y[pos..-1] + y[0..pos-1]
# => [4, 6, 0, 2]
mrks
  • 8,033
  • 1
  • 33
  • 62