Entonces estoy tratando de probar si una matriz de nombres de días de la semana está ordenada correctamente independientemente de dónde comience, por lo que

[Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday] => true
[Thursday, Friday, Saturday, Sunday, Monday, Tuesday, Wednesday] => true
[Monday, Thursday, Tuesday, Wednesday, Sunday, Friday, Saturday] => false

Esto es lo que tengo hasta ahora:

module Enumerable
  def sorted_by?
    each_cons(2).all? { |a, b| ((yield a) <=> (yield b)) <= 0 }
  end
end

Y

correct_week_days = {
  :monday => 0,
  :tuesday => 1,
  :wednesday => 2,
  :thursday => 3,
  :friday => 4,
  :saturday => 5,
  :sunday => 6
}

test_week_days_array.sorted_by? { |k, v| correct_week_days[k.to_sym] }

Esto devuelve verdadero en una matriz de cadenas de días de la semana sin clasificar. Sé que este enfoque es defectuoso, ya que no tendrá en cuenta la vuelta atrás.

  1. ¿Hay alguna manera de hacer esto?
  2. ¿Por qué vuelve verdadero?

Editar

Debería haber proporcionado un ejemplo real de los datos que estoy probando.

['monday', 'thursday', 'tuesday', 'wednesday', 'sunday', 'friday', 'saturday']

Este sería un ejemplo que debería fallar.

['wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'monday', 'tuesday']

Esto pasaría.

2
Kylee 4 feb. 2015 a las 19:57

6 respuestas

La mejor respuesta

Un algoritmo de dos líneas completamente simple que (opcionalmente) funciona para entradas que contienen menos de siete días.

Toma los días:

days = %w(monday tuesday wednesday thursday friday saturday sunday)
# => ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]

Duplique la matriz, de modo que contenga todas las sub-matrices válidas posibles:

days *= 2
# => ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]

Dados sus casos de entrada ...

case1 = %w(monday tuesday wednesday thursday friday saturday sunday)
case2 = %w(thursday friday saturday sunday monday tuesday wednesday)
case3 = %w(monday thursday tuesday wednesday sunday friday saturday)
case4 = %w(wednesday thursday friday saturday sunday monday tuesday)

Para cada caso de entrada, vea si hay algún segmento de elementos en la matriz days que coincide con su entrada:

days.each_cons(case1.length).include?(case1) # true
days.each_cons(case2.length).include?(case2) # true
days.each_cons(case3.length).include?(case3) # false
days.each_cons(case4.length).include?(case4) # true

Con todo, esta es una solución de dos líneas:

def days_in_order?(days)
  search_list = %w(monday tuesday wednesday thursday friday saturday sunday) * 2
  search_list.each_cons(days.length).include?(days)
end

Deberá manejar el caso en el que las mayúsculas de la entrada no coincidan ('monday' vs 'Monday'), pero esa es una extensión trivial. Si desea que esto solo acepte una matriz de entrada que tenga una duración de siete días, cambie each_cons(days.length) a each_cons(7).

4
meagar 4 feb. 2015 a las 17:56

¿Qué pasa con algún enfoque funcional? Considere el código a continuación (tenga en cuenta que podría estar escrito de una manera más compacta, dejé el gran if-than-else para facilitar la lectura):

DAYS = [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday]

def days_sorted_ok?(weekdays)
  if weekdays.empty? || weekdays.count == 1
    # only one day, so it is sorted well
    return true
  else
    # true, if the next day (weekdays[1]) is the next on the DAYS list
    if weekdays[1] == DAYS[(DAYS.index(weekdays[0]) + 1) % DAYS.count]
      if weekdays.count == 2 
        # only two days in the table, so the whole thing is sorted well
        return true
      else
        # check if the tail of the array is sorted well
        days_sorted_ok?(weekdays[1..-1])
      end
    else
      # second element is not a next weekday
      return false
    end
  end
end

Este es un método recurrente. Primero, verifica si la matriz está vacía o contiene solo un elemento. En este caso, lo trata como ordenado de buena manera. En el otro caso, comprueba si el segundo elemento de la lista es el siguiente de la lista DAYS (con módulo, para alternar los días de la semana). Si es cierto y la lista contiene solo 2 elementos, significa que está bien ordenada. En el otro caso, buscará de forma recursiva en el resto de la lista.

A continuación se muestran un par de pruebas:

days_sorted_ok? DAYS
#=> true
days_sorted_ok? [:tuesday, :wednesday, :thursday]
#=> true
days_sorted_ok? [:monday, :tuesday, :wednesday, :thursday, :friday, :sunday, :sunday]
#=> false
days_sorted_ok? [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday, :monday, :sunday]
#=> false
2
Grych 4 feb. 2015 a las 17:36

Aquí hay otra solución solo para recopilar más algoritmos. En resumen, encuentra una posición de lunes y la mueve junto con todos los elementos consecutivos al comienzo de una matriz (de hecho, es algo así como usar rotate, pero sin rotate) y luego compara con el orden correcto lista.

days = %w(monday tuesday wednesday thursday friday saturday sunday)

case1 = %w(monday tuesday wednesday thursday friday saturday sunday)
case2 = %w(thursday friday saturday sunday monday tuesday wednesday)
case3 = %w(monday thursday tuesday wednesday sunday friday saturday)
case4 = %w(wednesday thursday friday saturday sunday monday tuesday)

def days_in_order?(days)
  monday_index = days.index('monday')
  search_list = %w(monday tuesday wednesday thursday friday saturday sunday)
  search_list == days.slice(monday_index, days.size) | days[0...monday_index]
end

days_in_order?(case1) # true
days_in_order?(case2) # true
days_in_order?(case3) # false
days_in_order?(case4) # true

Para su información, este algoritmo es más rápido (~ 4s vs ~ 6s en mi máquina en 1000000 iteraciones para case3) que el de @meagar, sin embargo, su solución es más fácil de leer y creo que el rendimiento no es el objetivo en este caso :-)

PD. Escribí days.size en days.slice(monday_index, days.size) en lugar de days.size - monday_index porque de hecho no es necesario ya que el objetivo es simplemente alcanzar o superar el tamaño de una matriz.

0
trushkevich 5 feb. 2015 a las 09:03

Otra forma de hacerlo es utilizar el método Array # rotate! (o rotate).

Supuse que la matriz que se probará contiene los nombres de los siete días de la semana, en mayúsculas y nada más. Solo debemos comprobar si el pedido es correcto.

Primero, si el lector no está familiarizado con la construcción de una matriz de cadenas usando %w, aquí hay un ejemplo:

%w{ Monday Tuesday Wednesday Thursday Friday Saturday Sunday }
  #=> ["Monday", "Tuesday", "Wednesday", "Thursday",
       "Friday", "Saturday", "Sunday"] 

Código

def dow_sorted?(arr)
  %w{ Monday Tuesday Wednesday Thursday Friday Saturday Sunday }
    .rotate!(-arr.index('Monday')) == arr
end

Ejemplos

dow_sorted? %w{ Monday Tuesday Wednesday Thursday Friday Saturday Sunday }
  #=> true
dow_sorted? %w{ Thursday Friday Saturday Sunday Monday Tuesday Wednesday }
  #=> true
dow_sorted? %w{ Monday Thursday Tuesday Wednesday Sunday Friday Saturday }
  #=> false
dow_sorted? %w{ Friday Saturday Sunday Monday Wednesday Tuesday Thursday }
  #=> false

Explicación

Para el último ejemplo:

arr = %w{ Friday Saturday Sunday Monday Wednesday Tuesday Thursday }
  #=> ["Friday", "Saturday", "Sunday", "Monday",
  #    "Wednesday", "Tuesday", "Thursday"] 

ord = %w{ Monday Tuesday Wednesday Thursday Friday Saturday Sunday }
  #=> ["Monday", "Tuesday", "Wednesday", "Thursday",
  #    "Friday", "Saturday", "Sunday"] 

n = arr.index('Monday')
  #=> 3

a = ord.rotate(-3)
  #=> ["Friday", "Saturday", "Sunday", "Monday",
  #    "Tuesday", "Wednesday", "Thursday"] 

a == arr
  #=> false
0
Cary Swoveland 4 feb. 2015 a las 23:02

Mi solución reordena la matriz bajo prueba y la compara con una matriz ordenada correctamente (junto con un poco de limpieza de datos)

def test a
  # deal with an array of symbols or strings
  a = a.map do |day| day.downcase.to_sym end
  # make sure we at least have a monday in the array so we don't get stuck
  if a.include? :monday
    # reorder array so that monday is the first element
    while a.first != :monday
      a << a.shift
    end 
  end 
  # does it match an ideal ordered array?
  a == [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday]
end
0
Fred Willmore 4 feb. 2015 a las 19:41
def same_order?(arr1, arr2)
  raise 'Not same array' unless arr1.sort == arr2.sort

  arr1.length.times do
    arr1 = arr1.rotate
    return true if arr1 == arr2
  end

  return false
end


correct_order = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
a = ['wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'monday', 'tuesday']
b = ['monday', 'thursday', 'tuesday', 'wednesday', 'sunday', 'friday', 'saturday']
p same_order?(correct_order, a) #=> true
p same_order?(correct_order, b) #=> false
1
daremkd 4 feb. 2015 a las 17:58