4 votes

Découper des données discontinues en parties continues en Ruby

J'ai cet array discontinue :

a = [1, 2, 3, 7, 8, 10, 11, 12]

J'ai besoin qu'il soit un array d'arrays continus :

[[1, 2, 3], [7, 8], [10, 11, 12]]

Je parcours l'original, comparant chaque valeur à la dernière pour construire de nouveaux arrays :

parts = []
last = nil
a.each do |n|
  parts.push [] if last.nil? || last+1 != n
  parts.last.push n
  last = n
end

Cela semble sale et non digne de Ruby. Je suis intéressé par trouver une solution propre et élégante.

2voto

falsetru Points 109148

Version modifiée de @hirolau's.

a = [1, 2, 3, 7, 8, 10, 11, 12]
prev = a[0] - 1
a.slice_before { |cur|  [prev + 1 != cur, prev = cur][0] }.to_a
# => [[1, 2, 3], [7, 8], [10, 11, 12]]

prev = a[0] - 1
a.slice_before { |cur|
  discontinuous = prev + 1 != cur
  prev = cur
  discontinuous
}.to_a   
# => [[1, 2, 3], [7, 8], [10, 11, 12]]

2voto

sawa Points 62592
([a[0]] + a).each_cons(2).slice_before{|k, l| k + 1 != l}.map{|a| a.map(&:last)}
# => [[1, 2, 3], [7, 8], [10, 11, 12]]

1voto

hirolau Points 8596

Un exemple modifié de la documentation de l'itérable :

http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-slice_before

a = [1, 2, 3, 7, 8, 10, 11, 12]
prev = a.first
p a.slice_before { |e|
  prev, prev2 = e, prev
  prev2 + 1 != e
}.to_a # => [[1, 2, 3], [7, 8], [10, 11, 12]]

1voto

Neil Slater Points 11193

Il semble y avoir plusieurs façons de le faire.

a.each_cons(2).each_with_object([[ a.first ]]) do |pair, con_groups| 
  con_groups.push( [] ) if pair.reduce( :-) < -1
  con_groups.last.push( pair.last )
end

1voto

Kelvin Points 5810
arr.slice_before([]) {|elt, state|
  (elt-1 != state.last).tap{ state << elt }
}.to_a

Explication:

state est essentiellement une copie croissante de arr, et est initialisée à une copie de l'argument passé à slice_before. state.last représente l'élément précédent. Notez que dans la première itération, state.last est nil, et la comparaison fonctionne toujours.

J'utilise tap pour construire state tout en laissant le résultat de la comparaison être retourné. J'aurais pu utiliser begin/ensure, ou assigner à une variable, mais tap est plus court. L'ordre est important ici - je ne peux ajouter qu'après avoir fait la comparaison.

Un autre avantage est que je n'ai pas à faire référence à des variables externes à l'intérieur du bloc, ni à utiliser une version modifiée de arr.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X