2017-05-02 2 views
1

J'ai un tableau d'objets qui ressemble à ceci: https://i.stack.imgur.com/jaVcy.pngComment randomiser efficacement plusieurs éléments de tableau entre les index?

Chaque entrée est un objet dans ce tableau. Ce que je dois faire est de randomiser l'ordre de chaque élément qui n'est pas un titre. Chaque titre doit rester à l'index initial, mais les éléments entre deux titres doivent être randomisés. Dans l'image ci-jointe est une représentation de la façon dont il devrait ressembler.

La seule différence entre un titre et un élément régulier est que sa valeur est une expression régulière qui ressemble à ceci # H # [0-9] +

Alors, ce que je faisais était: J'itérer la tableau, en notant les index de chaque titre. Ensuite, parcourez le tableau d'index et divisez le tableau en plusieurs tableaux plus petits (un groupe pour chaque titre). Ensuite, recommencez l'opération à travers le tableau qui contient les tableaux fractionnés, découpez chaque tableau à partir de l'index 0 (supprimez l'élément de titre), mélangez ces valeurs, décalez le tableau et ajoutez l'élément titre au début.

Enfin, concaténez tous les tableaux de splittedArrayOfArrays dans le tableau dont j'ai besoin, à savoir current.choices.

L'exécution de trois itérations ne semble pas très sage en termes de performances, existe-t-il un autre moyen de randomiser uniquement des groupes d'éléments à partir d'un tableau?

Voici le code que je piraté ensemble pour le faire fonctionner:

    var headlineIndexes = []; 
        var splittedArrayOfArrays = []; 
        for (var ii = 0; ii < current.choices.length; ii++) { 
         if (regex.test(current.choices[ii].value)) { 
          headlineIndexes.push(ii); 
         } 
        } 
        for (var ii = 0; ii < headlineIndexes.length; ii++) { 
         //if there is another headlineIndex, split Array until that index 
         if (headlineIndexes[ii + 1]) { 
          splittedArrayOfArrays[ii] = current.choices.slice(headlineIndexes[ii], headlineIndexes[ii + 1]) 
         } 
         //if not, split until end of array 
         else { 
          splittedArrayOfArrays[ii] = current.choices.slice(headlineIndexes[ii]); 
         } 
        } 
        current.choices = []; 
        for (var ii = 0; ii < splittedArrayOfArrays.length; ii++) { 
         //remove first element and store in firstElem 
         var firstElem = splittedArrayOfArrays[ii].splice(0, 1); 
         //call shuffle with remaining elements, which shuffles the elements WITHOUT the headline 
         shuffle(splittedArrayOfArrays[ii]); 
         // re-add the headline as first elem of splittedArray 
         splittedArrayOfArrays[ii].unshift(firstElem[0]); 
        } 
        current.choices = splittedArrayOfArrays.reduce(function(prev, next) { 
         return prev.concat(next) ; 
        }); 

EDIT: Je réalisé qu'il n'y avait aucune raison de itérer sur les splittedArrayOfArrays, tout aurait pu être fait à partir de la seconde boucle. Je pense que c'est assez efficace pour un maximum de 40 éléments que j'aurais dans le tableau de toute façon. Voici le code final:

var headlineIndexes = []; 
        var splittedArrayOfArrays = []; 
        //save indexes at which we have headlines 
        for (var ii = 0; ii < current.choices.length; ii++) { 
         if (regex.test(current.choices[ii].value)) { 
          headlineIndexes.push(ii); 
         } 
        } 
        //split choices array into groups for each headline. 
        for (var ii = 0; ii < headlineIndexes.length; ii++) { 
         //if we have another headline, make new array with elements from current index to next index 
         if (headlineIndexes[ii + 1]) { 
          splittedArrayOfArrays[ii] = current.choices.slice(headlineIndexes[ii], headlineIndexes[ii + 1]) 
         } 
         //else, new array from current index to end of choices array 
         else { 
          splittedArrayOfArrays[ii] = current.choices.slice(headlineIndexes[ii]); 
         } 

         //remove first element which is the headline, store in firstElem 
         var firstElem = splittedArrayOfArrays[ii].splice(0, 1); 
         //shuffle the choices of the group 
         shuffle(splittedArrayOfArrays[ii]); 
         //add the first element back to the first position of the group 
         splittedArrayOfArrays[ii].unshift(firstElem[0]); 
        } 

        //delete choices array 
        current.choices = []; 
        //concatenate group arrays into the choices array 
        current.choices = splittedArrayOfArrays.reduce(function(prev, next) { 
         return prev.concat(next) ; 
        }); 

Répondre

0

Je me suis rendu compte qu'il n'y avait aucune raison d'itérer sur les splittedArrayOfArrays, tout aurait pu être fait à partir de la seconde boucle for. Je pense que c'est assez efficace pour un maximum de 40 éléments que j'aurais dans le tableau de toute façon. Voici le code final:

    var headlineIndexes = []; 
        var splittedArrayOfArrays = []; 
        //save indexes at which we have headlines 
        for (var ii = 0; ii < current.choices.length; ii++) { 
         if (regex.test(current.choices[ii].value)) { 
          headlineIndexes.push(ii); 
         } 
        } 
        //split choices array into groups for each headline. 
        for (var ii = 0; ii < headlineIndexes.length; ii++) { 
         //if we have another headline, make new array with elements from current index to next index 
         if (headlineIndexes[ii + 1]) { 
          splittedArrayOfArrays[ii] = current.choices.slice(headlineIndexes[ii], headlineIndexes[ii + 1]) 
         } 
         //else, new array from current index to end of choices array 
         else { 
          splittedArrayOfArrays[ii] = current.choices.slice(headlineIndexes[ii]); 
         } 

         //remove first element which is the headline, store in firstElem 
         var firstElem = splittedArrayOfArrays[ii].splice(0, 1); 
         //shuffle the choices of the group 
         shuffle(splittedArrayOfArrays[ii]); 
         //add the first element back to the first position of the group 
         splittedArrayOfArrays[ii].unshift(firstElem[0]); 
        } 

        //delete choices array 
        current.choices = []; 
        //concatenate group arrays into the choices array 
        current.choices = splittedArrayOfArrays.reduce(function(prev, next) { 
         return prev.concat(next) ; 
        }); 
1

Effectuer trois itérations ne semble pas très sage dans la performance [...]

Je ne vous inquiétez pas à ce sujet. À moins qu'il y ait des milliers de titres à regrouper et des centaines de milliers d'éléments à mélanger, cette routine n'aura aucune incidence sur la performance. Si vous voulez vraiment le modifier, vous pouvez le mettre en place, c'est-à-dire à l'intérieur du tableau d'origine, pour éviter d'avoir à copier les tableaux et à les assembler à nouveau.

+0

Oui, mais si je mélange le tableau d'origine, je perds les groupes dans le tableau. J'ai besoin que les index de titre ne changent pas, et seulement mélanger les éléments au sein des groupes (d'où le fractionnement des rangées, remuant et les rassemblant ensuite). –

+0

Vous ne mélangez que dans une certaine plage du tableau, entre deux titres. Vous deviez encore déterminer les positions des titres à l'avance bien sûr.Ensuite, au lieu de mélanger le tableau de l'index 0 à la fin, vous commencerez à partir de l'index juste après un titre jusqu'à l'avant le titre suivant, jusqu'à ce que vous ayez mélangé toutes les plages. – pfirpfel