2

I have a array of 2N elements. For example,[1,2,3,4,5,6,7,8]. Now I want to separate it into an array of random pairs (no repeats). The result may be:

[[1,3],[2,5],[4,8],[6,7]]

I try to code but I think it is not good. Any better ideas?

function arrSlice(arr) {
  if (arr.length % 2 !== 0) return 0;
  var
    newArr = [],
    //temp array.
    tmpArr = [];
  for (let i = 0; i < arr.length; i++) {
    if (!tmpArr.includes(arr[i])) {
      var rndIndex;
      do {
        rndIndex = Math.floor(Math.random() * (arr.length - (i + 1))) + (i + 1);
      } while (tmpArr.includes(arr[rndIndex]));
      newArr.push([arr[i], arr[rndIndex]]);
      tmpArr.push(arr[i]);
      tmpArr.push(arr[rndIndex]);
    }
  }
  return newArr;
}

var arr = [1, 2, 3, 4, 5, 6, 7, 8]
console.log(arrSlice(arr));
Nick
  • 4,820
  • 18
  • 31
  • 47
cloudyer
  • 23
  • 5

5 Answers5

1

You could create two functions, one to return new shuffled array and other one to slice it.

const arr = [1, 2, 3, 4, 5, 6, 7, 8];

function shuffle(arr) {
  return arr.reduce((r, e, i) => {
    r.splice(Math.random() * (i + 1), 0, e);
    return r;
  }, [])
}

function sliceArray(data, n = 2) {
  const arr = [];
  for (var i = 0; i < data.length; i += n) arr.push(data.slice(i, i + n))
  return arr;
}

const result = sliceArray(shuffle(arr), 2);
console.log(JSON.stringify(result))

Here is another approach you could first generate new empty array of sub-arrays and then loop data while there are still elements left and fill empty array.

function create(data, len) {
  data = data.slice();
  const result = Array.from(Array(Math.ceil(data.length / len)), () => []);
  let aN = 0;

  while (data.length) {
    result[aN].push(data.splice(parseInt(Math.random() * data.length), 1)[0]);
    if (result[aN].length == len) aN++;
  }

  return result;
}

console.log(JSON.stringify(create([1, 2, 3, 4, 5, 6, 7, 8], 2)))
console.log(JSON.stringify(create([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3)))
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
1

I would just remove random elements from the array and add them in pairs:

const random = end => Math.floor(Math.random() * end);

function pairedShuffle(array) {      
  const remove = () => array.splice(random(array.length), 1)[0];

  const result = [];
  while(array.length >= 2)
    result.push([remove(), remove()]);
  return result;
}

Alternatively this is a good usecase for generators:

function* pairs(iterable) {
  let prev = null;
  let i = 0;
  for(const el of iterable) {
    if(i++ % 2) yield [prev, el];
    prev = el;
  }
}

function* shuffle(iterable) {
  const arr = [...iterable];
  while(arr.length)
     arr.splice(random(arr.length), 1)[0];
}

Usable as:

const result = [...pairs(shuffle([1,2,3,4]))];
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
0

Something like this should work. Majority of this is copied from the Fisher-Yates shuffle here

function arrSlice(array) {
  var currentIndex = array.length, randomIndex, temporaryValue;
  var newArray = [], tempArray = [];

  while (currentIndex !== 0) {
    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
    
    tempArray.push(array[currentIndex]);
    if (tempArray.length == 2) {
      newArray.push(tempArray);
      tempArray = [];
    }
  }
  return newArray;
}

console.log(arrSlice([1, 2, 3, 4, 5, 6]));
Rolando Cruz
  • 2,834
  • 1
  • 16
  • 24
0

Using random sort and reduce chain

var data = [1, 2, 3, 4, 5, 6, 7, 8];

var res = data.slice()
  .sort(_ => Math.random() - 0.5)
  .reduce((a, c, i, arr) => (i % 2 ? a : a.concat([arr.slice(i, i + 2)])), [])

console.log(JSON.stringify(res))
charlietfl
  • 170,828
  • 13
  • 121
  • 150
0
function arrSlice (arr) {
    return arr
    .sort(() => Math.random() > .5)  //shuffle
    .map((element,index) => index % 2 ? false : [arr[index], arr[index+1]])
    .filter(Boolean);
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(arrSlice(arr));
cloudyer
  • 23
  • 5