2010-09-17 9 views
0

J'ai un tableau rare, par exemple:Remplissez tableau creux

rare = [[0,1], [2,3], [4,5], [7,8]] 

Je veux tracer un graphique avec ces données, chaque paire sont coordonnées du point. Comme vous pouvez le voir je n'ai pas de points pour x = 1, x = 3, x = 5, x = 6

Je veux remplir le tableau avec les valeurs précédentes, donc pour l'exemple ci-dessus je vais obtenir :

filled = [[0,1], [1,1], [2,3], [3,3], [4,5], [5,5], [6,5], [7,8] 

Comme vous pouvez le voir, pour calculer la valeur y, je prends simplement la dernière valeur y que j'ai utilisée.

Quelle est la meilleure approche pour y parvenir?

Répondre

6
Range.new(*rare.transpose.first.sort.values_at(0,-1)).inject([]){|a,i| 
    a<<[i, Hash[rare][i] || a.last.last] 
} 

explication étape par étape:

  1. rare.transpose.first.sort.values_at(0,-1) trouve min et max x ([0,7] dans votre exemple)
  2. Range.new() fait une gamme hors de celui-ci (0..7)
  3. inject itère à travers la gamme et pour chaque x renvoie la paire [x,y], où y est:
    1. y de tableau d'entrée, où défini
    2. y de paire précédemment évalué, où non

Note: voici quelques autres façons de trouver min et max x:

[:min,:max].map{|m| Hash[rare].keys.send m} 
rare.map{|el| el.first}.minmax # Ruby 1.9, by steenslag 
+0

Vous voulez nous parler à travers celui-là? Je suppose que ça va marcher mais ce n'est pas particulièrement lisible :) – Glenjamin

+0

Il échoue pour vide "rare". Je dirais qu'utiliser << avec injection est une sorte de triche, mais ce sera certainement plus rapide. – tokland

+0

@Glenjamin: J'ai donné le meilleur de moi-même :) @tokland: Merci pour le rapport de bug, et pourquoi pensez-vous que << << avec injecter c'est tricher? Tricher pourrait utiliser 'injecter' où' map' est logique (car je suis en train de mapper un tableau à un autre), mais j'avais besoin de valeurs précédentes, donc 'inject'. –

2
rare = [[0,1], [2,3], [4,5], [7,8]] 

filled = rare.inject([]) do |filled, point| 
    extras = if filled.empty? 
      [] 
      else 
      (filled.last[0] + 1 ... point[0]).collect do |x| 
       [x, filled.last[1]] 
      end 
      end 
    filled + extras + [point] 
end 

p filled 
# => [[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]] 
+0

note à @astropanic, ma solution et Wayne sont virt La même chose (seulement le sien était 4 minutes plus rapide). – tokland

+0

@tokland, :) Je serais hors de mon esprit si j'étais vous. Prenez-le moi: c'est effrayant ici! –

2

Une solution inject:

filled = rare.inject([]) do |filled_acc, (pair_x, pair_y)| 
    padded_pairs = unless filled_acc.empty?  
    last_x, last_y = filled_acc.last 
    (last_x+1...pair_x).map { |x| [x, last_y] } 
    end || [] 
    filled_acc + padded_pairs + [[pair_x, pair_y]] 
end 

En savoir plus sur Enumerable#inject et la programmation fonctionnelle avec Ruby here.

0
irb(main):001:0> rare = [[0,1], [2,3], [4,5], [7,8]] 
=> [[0, 1], [2, 3], [4, 5], [7, 8]] 
irb(main):002:0> r=rare.transpose 
=> [[0, 2, 4, 7], [1, 3, 5, 8]] 
irb(main):003:0> iv = (r[0][0]..r[0][-1]).to_a.select {|w| !r[0].include?(w) } 
=> [1, 3, 5, 6] 
irb(main):004:0> r[1][-1]=r[1][-2] 
=> 5 
irb(main):005:0> p (iv.zip(r[1]) + rare).sort 
[[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]] 
=> [[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]] 
Questions connexes