varias unir una texto sola separadas por perder para nombres filas datos convertir concatenar combinar coma columnas celdas apellidos ruby-on-rails ruby

ruby on rails - unir - Cómo combinar rangos de tiempo superpuestos(rangos de tiempo de unión)



unir nombres y apellidos en excel (8)

¿No solo desea buscar el primer valor más pequeño y el último último valor más grande del conjunto de matrices?

ranges = [Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00, Tue, 24 May 2011 16:30:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00, Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 09:00:00 CEST +02:00, Tue, 24 May 2011 15:30:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00] union = [ranges.collect(&:first).sort.first, ranges.collect(&:last).sort.last]

Tengo una matriz con varios rangos de tiempo dentro:

[Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00, Tue, 24 May 2011 16:30:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00, Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 09:00:00 CEST +02:00, Tue, 24 May 2011 15:30:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00]

Quiero obtener la misma matriz con los rangos de tiempo superpuestos combinados, por lo que la salida para este caso será:

[Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00, Tue, 24 May 2011 15:30:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00]

Así que crea un nuevo intervalo de tiempo cuando los intervalos de tiempo se superponen, y así sucesivamente. Si no se superponen se mantendrán separados. Otro ejemplo:

Entrada:

[Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00, Tue, 24 May 2011 16:00:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00]

Salida (será la misma porque no se superponen):

[Tue, 24 May 2011 08:00:00 CEST +02:00..Tue, 24 May 2011 13:00:00 CEST +02:00, Tue, 24 May 2011 16:00:00 CEST +02:00..Tue, 24 May 2011 18:00:00 CEST +02:00]

Estaba pensando en un enfoque recursivo, pero necesito una guía aquí ...


Algún tipo de algoritmo que podría ayudar:

Sort range array by start time (r1, r2, r3, r4, .. rn) for each range pair [r1, r2], [r2, r3] .. [rn-1, rn]: if r1_end > r2_start: # they overlap add [r1_start, r2_end] to new range array else: # they do not overlap add [r1] and [r2] to new range array (no changes) startover with the new range array until no more changes


Buscando un poco he encontrado un código que hace el truco:

def self.merge_ranges(ranges) ranges = ranges.sort_by {|r| r.first } *outages = ranges.shift ranges.each do |r| lastr = outages[-1] if lastr.last >= r.first - 1 outages[-1] = lastr.first..[r.last, lastr.last].max else outages.push(r) end end outages end

Una muestra (¡trabajando con rangos de tiempo también!):

ranges = [1..5, 20..20, 4..11, 40..45, 39..50] merge_ranges(ranges) => [1..11, 20..20, 39..50]

Se encuentra aquí: http://www.ruby-forum.com/topic/162010


Dada una función que devuelve truey si dos rangos se superponen:

def ranges_overlap?(a, b) a.include?(b.begin) || b.include?(a.begin) end

(Esta función es cortesía de sepp2k y steenslag )

y una función que combina dos rangos superpuestos:

def merge_ranges(a, b) [a.begin, b.begin].min..[a.end, b.end].max end

entonces esta función, dada una matriz de rangos, devuelve una nueva matriz con todos los rangos superpuestos combinados:

def merge_overlapping_ranges(overlapping_ranges) overlapping_ranges.sort_by(&:begin).inject([]) do |ranges, range| if !ranges.empty? && ranges_overlap?(ranges.last, range) ranges[0...-1] + [merge_ranges(ranges.last, range)] else ranges + [range] end end end


El gem range_operators hace un trabajo maravilloso al agregar características faltantes a la clase Ruby Range . Es mucho más pequeño que agregar la gema completa de facets .

En su caso, la solución sería el método rangify , que se agrega a la clase Array y haría exactamente lo que está buscando.



La respuesta marcada funciona bien, excepto en algunos casos de uso. Uno de tales casos de uso es

[Tue, 21 June 13:30:00 GMT +0:00..Tue, 21 June 15:30:00 GMT +00:00, Tue, 21 June 14:30:00 GMT +0:00..Tue, 21 June 15:30:00 GMT +00:00]

La condición en ranges_overlap no maneja este caso de uso. Así que escribí esto

def ranges_overlap?(a, b) a.include?(b.begin) || b.include?(a.begin) || a.include?(b.end) || b.include?(a.end)|| (a.begin < b.begin && a.end >= b.end) || (a.begin >= b.begin && a.end < b.end) end

Esto está manejando todos los casos de borde para mí hasta ahora.


La solución ofrecida por @ wayne-conrad es muy buena. Lo implementé por un problema, me topé. Luego implementé una versión iterativa y comparé las dos. Aparece, la versión iterativa es más rápida. Nota: uso ActiveSupport para ActiveSupport de Range#overlaps? y los ayudantes del tiempo, pero es trivial implementar una versión de Ruby puro.

require ''active_support/all'' module RangesUnifier extend self # ranges is an array of ranges, e.g. [1..5, 2..6] def iterative_call(ranges) ranges.sort_by(&:begin).reduce([ranges.first]) do |merged_ranges, range| if merged_ranges.last.overlaps?(range) merged_ranges[0...-1] << merge_ranges(merged_ranges.last, range) else merged_ranges << range end end end def recursive_call(ranges) return ranges if ranges.size == 1 if ranges[0].overlaps?(ranges[1]) recursive_call [merge_ranges(ranges[0], ranges[1]), *ranges[2..-1]] else [ranges[0], *recursive_call(ranges[1..-1])] end end def merge_ranges(a, b) [a.begin, b.begin].min..[a.end, b.end].max end end five_hours_ago = 5.hours.ago four_hours_ago = 4.hours.ago three_hours_ago = 3.hours.ago two_hours_ago = 2.hours.ago one_hour_ago = 1.hour.ago one_hour_from_now = 1.hour.from_now two_hours_from_now = 2.hours.from_now three_hours_from_now = 3.hours.from_now four_hours_from_now = 4.hours.from_now five_hours_from_now = 5.hours.from_now input = [ five_hours_ago..four_hours_ago, three_hours_ago..two_hours_from_now, one_hour_ago..one_hour_from_now, one_hour_from_now..three_hours_from_now, four_hours_from_now..five_hours_from_now ] RangesUnifier.iterative_call(input) #=> [ # 2017-08-21 12:50:50 +0300..2017-08-21 13:50:50 +0300, # 2017-08-21 14:50:50 +0300..2017-08-21 20:50:50 +0300, # 2017-08-21 21:50:50 +0300..2017-08-21 22:50:50 +0300 # ] RangesUnifier.recursive_call(input) #=> [ # 2017-08-21 12:50:50 +0300..2017-08-21 13:50:50 +0300, # 2017-08-21 14:50:50 +0300..2017-08-21 20:50:50 +0300, # 2017-08-21 21:50:50 +0300..2017-08-21 22:50:50 +0300 # ] n = 100_000 Benchmark.bm do |x| x.report(''iterative'') { n.times { RangesUnifier.iterative_call(input) } } x.report(''recursive'') { n.times { RangesUnifier.recursive_call(input) } } end # => # user system total real # iterative 0.970000 0.000000 0.970000 ( 0.979549) # recursive 0.540000 0.010000 0.550000 ( 0.546755)