2011-05-22 2 views
1

j'ai un dictionnaire de données comme ceci:propriétés tableau Shuffling en JavaScript

var data = { 
    'text1': 1, 
    'text2': 2, 
    'text3': 3, 
    ... 
    'text20': 20 
]; 

je dois choisir une sélection aléatoire de ces touches, puis mélanger ses valeurs. Dans l'exemple, il faut écrire quelque chose comme ceci:

> console.log(choose(data, 5)); 
[ { key: 'text15', value: 8 }, 
{ key: 'text6', value: 3 }, 
{ key: 'text3', value: 15 }, 
{ key: 'text19', value: 6 }, 
{ key: 'text8', value: 19 } ] 

Pour l'instant j'extraire les clés dans un autre tableau et le tri par Math.random() mais je suis bloqué à swaping les valeurs car aucune clé doit avoir la même valeur qu'au départ.

Comment changer les clés/valeurs ici?

Merci

+0

est-ce avec ou sans remplacement? par exemple. la valeur avec 'text8' peut-elle apparaître deux fois? – ninjagecko

+0

Non, ne peut pas avoir de valeurs répétées. –

+0

Que voulez-vous dire par «aucune clé ne devrait avoir la même valeur qu'au départ»? Le tri également par une fonction clé 'Math.random()' ne vous donne pas de permutation avec une probabilité égale; Cela dépend de l'algorithme de tri utilisé. Vous devez obtenir N clés via 'Math.random()', les stocker, puis les trier. – ninjagecko

Répondre

1

Je mis en place une solution possible en utilisant underscore.js pour simplifier la traversée de l'objet et des tableaux d'une manière croix navigateur:

var data = { 
    text1: 1, 
    text2: 2, 
    text3: 3, 
    text4: 4, 
    text5: 5, 
    text6: 6, 
    text7: 7, 
    text8: 8, 
    text9: 9, 
    text10: 10 
}; 

function choose(data, num) 
{ 
    var keys = _.sortBy(
        _.keys(data), 
        function(k) 
        { 
         return (Math.random() * 3) - 1; 
        } 
       ), 
     results = [], 
     k1, k2; 
    if (num > keys.length) { 
     throw new Error('Impossible to retrieve more values than exist'); 
    } 
    while (results.length < num) { 
     k1 = k2 || keys.pop(); 
     k2 = keys.pop(); 
     results.push({key:k1, value: data[k2]}); 
    } 
    return results; 
} 

console.log(choose(data, 5)); 

Ce n'est pas nécessairement une approche optimale, mais il semble répondre vos besoins. Je prends d'abord toutes les clés et les trier au hasard. Je boucle ensuite à travers les clés aléatoires en créant un nouvel objet avec une clé et la valeur des touches suivantes. De cette façon, vous aurez toujours une valeur différente associée à chaque clé. Si vous en avez besoin pour travailler quand la valeur de num est passée à la fonction == le nombre de clés dans les données, alors vous devrez ajouter un peu plus de code - je laisserai cela comme un exercice pour le lecteur :)

Vous pouvez avoir un jeu avec ce code sur jsFiddle:

http://jsfiddle.net/zVyQW/1/

+0

Très similaire à ma solution, mais le || Truc est mieux que l'incrémentation de deux compteurs. Je vous donne les points. –

+0

Cela échoue si vous voulez exactement n éléments comme vous auriez besoin n + 1 clés pour obtenir la valeur n. – Gumbo

+0

@Gumbo - comme vous pouvez le voir si vous lisez ce que j'ai écrit sous le code, cela a été laissé comme un exercice (plutôt trivial) pour le lecteur ... – vitch

0

Utilisez une implémentation de hasard qui randomise un ensemble discret de valeurs, telles que Math.rand seen here. Pour chaque index, randomisez Math.rand(index, length-1) pour obtenir une liste d'index aléatoires, l'emplacement de tous les indices va changer.

1

Vous pouvez le faire:

  • recueillir les noms et les valeurs correspondantes dans deux tableaux noms et valeurs
  • mélanger les deux tableaux indépendamment les uns des autres
  • prendre les premiers n articles des deux réseaux et les combiner

Voici un exemple d'implémentation:

Array.prototype.shuffle = function() { 
    for (var i=this.length-1, j, tmp; i>0; i--) { 
     j = Math.round(Math.random()*i); 
     tmp = this[i], this[i] = this[j], this[j] = tmp; 
    } 
    return this; 
}; 

function choose(data, number) { 
    var names = [], values = [], pick = []; 
    for (var name in data) { 
     if (data.hasOwnProperty(name)) { 
      names.push(name); 
      values.push(data[name]); 
     } 
    } 
    names = names.shuffle(), values = values.shuffle(); 
    for (var i=Math.min(number >>> 0, names.length-1); i>=0; i--) { 
     pick.push({key: names[i], value: values[i]}); 
    } 
    return pick; 
} 
0

un moment que cela a été répondu, mais je travaillais et brassage constaté ce qui suit de loin la plus rapide mise en œuvre avec une distribution uniformément aléatoire.

C'est rapide car il fait seulement un appel à Math.random à chaque itération, tout le reste se fait par accès aux propriétés. Il ne modifie pas le tableau, il suffit de réaffecter les valeurs.

function shuffle(a) { 
    var t, j, i=a.length, rand=Math.random; 

    // For each element in the array, swap it with a random 
    // element (which might be itself) 
    while (i--) { 
     k = rand()*(i+1)|0; 
     t = a[k]; 
     a[k]=a[i]; 
     a[i]=t; 
    } 
    return a; 
    } 
0

Il utilise une combinaison de trois fonctions (y compris la méthode de prototype Array Shuffle).

Voici le code complet:

var obj = { 
    "red":"RED", 
    "blue":"BLUE", 
    "green":"GREEN", 
    "yellow":"YELLOW", 
    "purple":"PURPLE" 
}; 

Array.prototype.shuffle = function(){ 
    for (var i = 0; i < this.length; i++){ 
     var a = this[i]; 
     var b = Math.floor(Math.random() * this.length); 
     this[i] = this[b]; 
     this[b] = a; 
    } 
} 

obj = shuffleProperties(obj); // run shuffle 

function shuffleProperties(obj) { 
    var new_obj = {}; 
    var keys = getKeys(obj); 
    keys.shuffle(); 
    for (var key in keys){ 
     if (key == "shuffle") continue; // skip our prototype method 
     new_obj[keys[key]] = obj[keys[key]]; 
    } 
    return new_obj; 
} 

function getKeys(obj){ 
    var arr = new Array(); 
    for (var key in obj) 
     arr.push(key); 
    return arr; 
} 


for(key in obj){ 
    alert(key); 
} 

Check all post, Cordialement.