2017-06-27 7 views
1

J'itérer sur les permutations d'une liste (18 articles) comme ceci:recenseurs ruby: sauter immédiatement plusieurs itérations (ou commencer à itérer de n)

List = [item0..item18] # (unpredictable) 
Permutation_size = 7 
Start_at = 200_000_000 

for item, i in List.repeated_permutation(Permutation_size).each_with_index 
    next if i < Start_at 
    # do stuff 
end 

Start_at est utilisé pour reprendre à partir d'un état précédemment enregistré donc c'est toujours différent mais il faut presque 200s pour atteindre 200 millions donc je me demande s'il y a un moyen plus rapide d'ignorer plusieurs itérations ou de commencer à l'itération n (convertir l'énumérateur en un tableau prend encore plus de temps). Sinon, un moyen de créer un repeated_permutation(n).each_with_index personnalisé (qui donne des résultats dans le même ordre) serait également apprécié.

Sentez-vous libre de me rediriger vers une réponse existante (je n'ai pas trouvé)

PS. (Ce que je suis venu avec)

class Array 
    def rep_per_with_index len, start_at = 0 
    b = size 
    raise 'btl' if b > 36 
    counter = [0]*len 
    # counter = (start_at.to_s b).split('').map {|i| ''.include?(i) ? i.to_i : (i.ord - 87)} #this is weird, your way is way faster 
    start_at.to_s(b).chars.map {|i| i.to_i b} 
    counter.unshift *[0]*(len - counter.length) 
    counter.reverse! 
    i = start_at 
    Enumerator.new do |y| 
     loop do 
     y << [counter.reverse.map {|i| self[i]}, i] 
     i += 1 
     counter[0] += 1 
     counter.each_with_index do |v, i| 
      if v >= b 
      if i == len - 1 
       raise StopIteration 
      else 
       counter[i] = 0 
       counter[i + 1] += 1 
      end 
      else 
      break 
      end 
     end 
     end 
    end 
    end 
end 
+0

Quelle est la taille maximale approximative de 'list'? –

+0

Idéalement, je voudrais une solution générale mais maintenant la taille est toujours 18 –

Répondre

1

I première construction d'une méthode d'assistance, change_base, avec trois arguments:

  • off, la base 10 de décalage dans la séquence de permutations répétées de la donnée tableau arr,
  • m, une base de système numérique; et
  • p, la taille de permutation.

Le procédé effectue trois étapes pour construire une matrice off_m:

  • convertit off à la base m (radix m);
  • sépare les chiffres de la valeur de base m en un tableau; et
  • si nécessaire, remplit le tableau avec 0 s pour le rendre de taille p.

En réglant m = arr.size, chaque chiffre de off_m est un décalage dans arr, de sorte que les cartes de off_m la base 10 de décalage à une permutation unique de taille p.

def change_base(m, p, off) 
    arr = off.to_s(m).chars.map { |c| c.to_i(m) } 
    arr.unshift(*[0]*(p-arr.size)) 
end 

Quelques exemples:

change_base(16, 2, 32) 
    #=> [2, 0] 
change_base(16, 3, 255) 
    #=> [0, 15, 15] 
change_base(36, 4, 859243) 
    #=> [18, 14, 35, 31] 
18*36**3 + 14*36**2 + 35*36**1 + 31 
    #=> 859243 

Cette mise en œuvre de change_base exige que m <= 36. Je suppose que cela sera suffisant, mais des algorithmes sont disponibles pour convertir les nombres de base 10 en nombres avec des bases arbitrairement grandes.

Nous construisons maintenant une méthode qui accepte le tableau donné, arr, la taille de chaque permutation, p et un décalage de base 10 donné dans la séquence de permutations. La méthode renvoie une permutation, à savoir, un tableau de taille p dont les éléments sont des éléments de arr.

def offset_to_perm(arr, p, off) 
    arr.values_at(*change_base(arr.size, p, off)) 
end 

Nous pouvons maintenant essayer ceci avec un exemple.

arr = (0..3).to_a 
p = 2 

(arr.size**p).times do |off| 
    print "perm for off = " 
    print " " if off < 10 
    print "#{off}: " 
    p offset_to_perm(arr, p, off) 
end 

perm for off = 0: [0, 0] 
perm for off = 1: [0, 1] 
perm for off = 2: [0, 2] 
perm for off = 3: [0, 3] 
perm for off = 4: [0, 1] 
perm for off = 5: [1, 1] 
perm for off = 6: [2, 1] 
perm for off = 7: [3, 1] 
perm for off = 8: [0, 2] 
perm for off = 9: [1, 2] 
perm for off = 10: [2, 2] 
perm for off = 11: [3, 2] 
perm for off = 12: [0, 3] 
perm for off = 13: [1, 3] 
perm for off = 14: [2, 3] 
perm for off = 15: [3, 3] 

Si nous voulons commencer à, disons, décalage 5, on peut écrire:

i = 5 
p offset_to_perm(arr, p, i) 
[1, 1] 
i = i.next #=> 6 
p offset_to_perm(arr, p, i) 
[2, 1] 
... 
+0

J'ai fait la même chose (comme un énumérateur) mais le mien est ~ 6 fois plus lent juste à itération que [...]. Repeat_permutation (n) .with_index', avez-vous testé la vitesse? –

+0

J'avoue que je n'ai pas regardé votre code jusqu'à maintenant. Oui, les approches sont assez similaires. Puisque vous avez du code de travail, je vous suggère de le déplacer de votre question à une réponse (et de préférence ajouter quelques repères). Je n'ai fait aucun test de performance. –