J'ai besoin de mapper un certain nombre d'identifiants et de plages d'identifiants à des valeurs uniques. Je souhaite stocker toute la structure dans un seul objet.

Est-ce que ce qui suit est une manière sensée de le faire? Quelle est la meilleure façon de rechercher les clés par une seule valeur entière pour renvoyer la valeur correspondante?

large array = [
   {[3110..3220, 10200, 43680] =>   'A0300'},
   {[5200, 7100..8990, 9100..9900] => 'B0400'},
   {[17110..18121, 20160, 2210..22290] => 'C0600'}
]
-1
jbk 15 nov. 2017 à 08:20

4 réponses

Meilleure réponse

Un format raisonnable pour stocker les données serait un simple hachage simple:

input = { [3110..3220, 10200, 43680] =>  'A0300',
          [5200, 7100..8990, 9100..9900] => 'B0400',
          [17110..18121, 20160, 2210..22290] => 'C0600' }

Pour rechercher l'élément, on peut utiliser la casse égale ou triple égale. Heureusement, il est également implémenté pour les entiers:

value = 7300
result = input.detect { |k, _| k.any? { |r| r === value } }
result ? result.last : nil
#⇒ "B0400"
2
Aleksei Matiushkin 15 nov. 2017 à 05:33

Il est inutile d'utiliser des tableaux et / ou des plages comme clé de hachage, lorsque vous souhaitez rechercher les données à une valeur unique. L'avantage d'un hachage est que, étant donné une clé, vous pouvez trouver une valeur rapidement. Dans votre cas, vous devrez parcourir le hachage de manière séquentielle pour trouver l'entrée. Dans ce cas, il serait plus judicieux d'utiliser un tableau de paires, le premier composant décrivant la plage et le second composant décrivant l'ID.

Si vous souhaitez utiliser un hachage, vous devez créer une entrée correspondante pour chaque valeur entière possible.

Si vous savez que les valeurs entières ne peuvent pas être supérieures à une certaine taille, vous pouvez créer un tableau fragmenté, où la valeur entière est la position d'index et l'ID est le contenu de la cellule du tableau. C'est le plus rapide, mais prend bien sûr un peu de place.

0
user1934428 15 nov. 2017 à 07:42

Si les valeurs étaient câblées, on pourrait utiliser une instruction case.

def look_it_up(n)
  case n
  when 7100..8990, 9100..9900, 5200
    'B0400'
  when 17110..18121, 22100..22290, 20160
    'C0600'
  when 3110..3220, 10200, 43680
    'A0300'
  else
    nil
  end
end

look_it_up 10200 #=> "A0300"
look_it_up  9135 #=> "B0400"
look_it_up 22100 #=> "C0600"
look_it_up  3079 #=> nil

En supposant que n est distribué un peu uniformément, j'ai, pour des raisons d'efficacité, ordonné les clauses when par nombre décroissant de nombres inclus, et dans chaque clause when, j'ai mis les plages en premier et a ordonné ces gammes par taille décroissante.

Si les valeurs ne sont pas nécessairement câblées, on pourrait utiliser find/detect, comme l'a fait @mudasobwa.

Si de nombreuses recherches devaient être effectuées, je suggérerais de construire un hachage dont les clés sont des entiers.

def init_arr(*args)
  args.each do |*a, value|
    a.each do |e|
      if e.is_a?(Range)
        e.each { |n| @h[n] = value }
      else
        @h[e] = value
      end
    end
  end
end

Ensuite, pour tout n, @h[n] donne sa valeur. Par exemple,

@h = {}
init_arr [1..4, 8..10, 11, "cat"]
  @h #=> {1=>"cat", 2=>"cat", 3=>"cat", 4=>"cat", 8=>"cat", 9=>"cat",
     #    10=>"cat", 11=>"cat"}
init_arr [13..14, 7, "dog"]
  @h #=> {1=>"cat", 2=>"cat", 3=>"cat", 4=>"cat", 8=>"cat", 9=>"cat",
     #    10=>"cat", 11=>"cat", 13=>"dog", 14=>"dog", 7=>"dog"}

Alors dire),

@h[13]
  #=> "dog"
@h[11]
  #=> "cat"
@h[12]
  #=> nil

Naturellement, cela suppose que @h.size est gérable.

On pourrait aussi construire un tableau de recherche, disons @arr, qui devrait être plus rapide que d'utiliser un hachage (bien qu'il puisse consommer beaucoup plus de mémoire qu'un hachage). @arr[n] renverrait la valeur de n ou nil s'il n'y a pas de valeur correspondante. Si certaines valeurs étaient négatives, ou si les plus petites n étaient assez grandes, on écrirait à la place @arr[n+@offset], où @offset est la valeur évidente.

1
Cary Swoveland 17 nov. 2017 à 07:53

Non. Il n'est pas nécessaire de séparer chaque paire clé-valeur en un hachage différent comme vous l'avez fait. De plus, vous utilisez le hachage d'une manière incorrecte. Une valeur-clé de hachage n'a pas besoin d'être un-à-un. Il vaut mieux avoir quelque chose comme ça:

{
  3110..3220 => 'A0300',
  10200 => 'A0300',
  43680 => 'A0300',
  5200 => 'B0400',
  7100..8990 => 'B0400',
  9100..9900 => 'B0400',
  17110..18121 => 'C0600',
  20160 => 'C0600',
  2210..22290 => 'C0600',
}

Mais je suppose que vous posez en fait une question X-Y, et ma réponse ci-dessus n'est toujours pas la meilleure solution pour vous.

1
sawa 15 nov. 2017 à 07:31
47299921