How to rearrange an array by indices array?

前端 未结 9 2028
故里飘歌
故里飘歌 2021-02-01 19:12

Given an array arr and an array of indices ind, I\'d like to rearrange arr in-place to satisfy the given indices. For exa

9条回答
  •  谎友^
    谎友^ (楼主)
    2021-02-01 19:34

    This answer has been updated to satisfy OP's conditions

    In this answer there are no temp arrays and ind array doesn't get re-ordered or sorted by any means. All replacing operations are done in a single pass. getItemIndex function receives only a shallow portion of the ind array to work with. It's just done by harnessing all the information hidden in the ind array.

    It's key to understand that the ind array keeps all history for us.

    We have the following information by examining the ind array.

    1. By looking at the items we find the index map of the corresponding item at arr array.
    2. Each items index tells us how many swaps done before. We get history.
    3. Each items index also tells if there was a previous swap related with the current index position where did the previous element go. We can do like ind.indexOf(i); Anyways here is the code;

    I have added a few functions like Array.prototype.swap() to make the code interpreted easier. Here is the code.

    Array.prototype.swap = function(i,j){
      [this[i],this[j]] = [this[j],this[i]];
      return this;
    };
    
    function getItemIndex(a,i){
      var f = a.indexOf(i);
      return f !=-1 ? getItemIndex(a,f) : i;
    }
    
    function sort(arr,ind){
      ind.forEach((n,i,x) => x.indexOf(i) > i ? arr.swap(i,x[i]) // item has not changed before so we can swap 
                                              : arr.swap(getItemIndex(ind.slice(0,i),i),x[i])); // item has gone to somwhere in previous swaps get it's index and swap
      return arr;
    }
    
    var arr = ["A", "B", "C", "D", "E", "F"],
        ind = [4, 0, 5, 2, 1, 3];
    
    
    console.log(sort(arr,ind),ind);

    Ok the very final version of this code is this. It is very simplified and includes a test case with 26 letters. Each time you run you will get a different purely random unique indexes map.

    Array.prototype.swap = function(i,j){
      i !=j && ([this[i],this[j]] = [this[j],this[i]]);
      return this;
    };
    
    Array.prototype.shuffle = function(){
      var i = this.length,
          j;
      while (i > 1) {
        j = ~~(Math.random()*i--);
        [this[i],this[j]] = [this[j],this[i]];
      }
    return this;
    };
    
    var   arr = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"],
          ind = (new Array(arr.length)).fill("").map((e,i) => e = i).shuffle();
    console.log(JSON.stringify(arr));
    console.log(JSON.stringify(ind));
    
    function getItemIndex(a,i,j){
      var f = a.indexOf(i);
      return f < j ? getItemIndex(a,f,j) : i;
    }
    
    function sort(arr,ind){
      ind.forEach((n,i,x) => arr.swap(getItemIndex(ind,i,i),n));
      return arr;
    }
    console.log(JSON.stringify(sort(arr,ind)));
    console.log(JSON.stringify(ind));

    So ok as per the comment from Trincot here it goes with an iterative getItemIndex() function.

    Array.prototype.swap = function(i,j){
      i !=j && ([this[i],this[j]] = [this[j],this[i]]);
      return this;
    };
    
    Array.prototype.shuffle = function(){
      var i = this.length,
          j;
      while (i > 1) {
        j = ~~(Math.random()*i--);
        [this[i],this[j]] = [this[j],this[i]];
      }
    return this;
    };
    
    var   arr = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"],
          ind = (new Array(arr.length)).fill("").map((e,i) => e = i).shuffle();
    console.log(JSON.stringify(arr));
    console.log(JSON.stringify(ind));
    
    function getItemIndex(a,i){
      var f = a.indexOf(i),
          j;
      if (f >= i) return i; // this element hasn't been moved before.
      while (f < i) {       // this element has been swapped so get this elements current index
      	j = f;
      	f = a.indexOf(f);
      }
      return j;
    }
    
    function sort(arr,ind){
      ind.forEach((n,i,x) => arr.swap(getItemIndex(ind,i),n));
      return arr;
    }
    console.log(JSON.stringify(sort(arr,ind)));
    console.log(JSON.stringify(ind));

提交回复
热议问题