简体   繁体   中英

How does one pick the col/row or x/y coordinates of N random elements of a 2D matrix without item/coordinate duplicates?

I have a 2D matrix, here's an example data = [["a", "b", "c", "d"], ["e", "g"], ["i", "j", "k"]]

I need to get N random (x, y) indexes without duplicates.

I already asked a different question same context and this is the solution to pick 2 x, y combos

const data = [["a", "b", "c", "d"], ["e", "g"], ["i", "j", "k"]];

function combinations(data) {
  const i11 = Math.floor(Math.random() * data.length);
  const i12 = Math.floor(Math.random() * data[i11].length);

  const dataLength = data[i11].length > 1 ? data.length : data.length - 1;

  let i21 = Math.floor(Math.random() * dataLength);
  if (i21 >= i11 && data[i11].length === 1) ++i21;

  const innerDataLength = i21 === i11 ? data[i21].length - 1 : data[i21].length;
  let i22 = Math.floor(Math.random() * innerDataLength);
  if (i21 === i11 && i22 >= i12) ++i22;
  
  return [[i11, i12], [i21, i22]];
}

console.log(combinations(data));

for (let i = 0; i < 10000; ++i) {
    const [[i11, i12], [i21, i22]] = combinations(data);
    if (i11 === i21 && i12 == i22) console.log('Test failed!');
}

 function pickNOf(list, n) { // - create a new shallow array copy. // - does decouple the original reference, thus it // prevents its further mutation by eg `splice`. list = Array.from(list); // - creates and returns an array of the desired length // by a mapping task which constantly slices random // items from the shallow array copy. return Array.from({ length: n }, () => list.splice( // - `splice` does mutate the list by removing a // single item from its randomly chosen index. Math.floor(Math.random() * list.length), 1 )[0]); } function pickNUniqueItemsFromNestedArray(arr, n) { // - flatten nested array structure, // - channel it through a `Set` in order // to keep just unique values, // - return the result of the forwarded // `pickNOf` call. return pickNOf([...new Set( arr.flat(Infinity) )], n); } const data = [ ["a", "b", "c", "d"], ["e", "g"], ["i", "j", "k"] ]; console.log( "pickNUniqueItemsFromNestedArray(data, 9) ...", pickNUniqueItemsFromNestedArray(data, 9) ); console.log( "pickNUniqueItemsFromNestedArray(data, 5) ...", pickNUniqueItemsFromNestedArray(data, 5) ); console.log( "pickNUniqueItemsFromNestedArray(data, 3) ...", pickNUniqueItemsFromNestedArray(data, 3) );
 .as-console-wrapper { min-height: 100%!important; top: 0; }

Edit due to ...

Thank you it works, but i need indexes – Amine

But that's not what the question's topic doe state ... "How to pick N random elements from a 2D matrix without duplicates in javascript?" Nevertheless I will provide a second solution which utilizes the first given approach in order to fully meet the OP's requirements. – Peter Seliger

In order to meet the OP's requirements the above given approach changes slightly to ...

 function pickNOf(list, n) { // - create a new shallow array copy. // - does decouple the original reference, thus it // prevents its further mutation by eg `splice`. list = Array.from(list); // - creates and returns an array of the desired length // by a mapping task which constantly slices random // items from the shallow array copy. return Array.from({ length: n }, () => list.splice( // - `splice` does mutate the list by removing a // single item from its randomly chosen index. Math.floor(Math.random() * list.length), 1 )[0]); } function pickNUniqueIndexTuplesFrom2dMatrix(matrix, n) { // - create a flat array of any of a // matrix' index coordinates/tuples. return pickNOf( matrix.flatMap((arr, rowIdx) => arr.map((_, colIdx) => [rowIdx, colIdx]) ), n ); } const data = [ ["a", "b", "c", "d"], ["e", "g"], ["i", "j", "k"] ]; console.log( "pickNUniqueIndexTuplesFrom2dMatrix(data, 9) ...", pickNUniqueIndexTuplesFrom2dMatrix(data, 9) ); console.log( "pickNUniqueIndexTuplesFrom2dMatrix(data, 5) ...", pickNUniqueIndexTuplesFrom2dMatrix(data, 5) ); console.log( "pickNUniqueIndexTuplesFrom2dMatrix(data, 3) ...", pickNUniqueIndexTuplesFrom2dMatrix(data, 3) );
 .as-console-wrapper { min-height: 100%!important; top: 0; }

Note

Despite or maybe even because of the misunderstanding it might become more clear that the base approach itself does not change. Which is ... pick n random items from an array without duplicates ... and ...

  • Split the main task into more specialized sub tasks. (Like demonstrated with the implementation of pickNOf which solves a single problem perfectly, thus it does not need to be refactored.)

  • The other task/s has/have to transform the input data in a way that it can be passed to the specialized task of picking n random items from an array without duplicates (which hopefully got proofed by the two different approaches each targeting a different requirement).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM