Randomly divide an array of objects into two equal arrays

I am facing a challenge with an array of objects;

let persons = [
    {id: 1, name: "..."},
    {id: 2, name: "..."},
    {id: 3, name: "..."},
    {id: 4, name: "..."},
    {id: 5, name: "..."},
    {id: 6, name: "..."},
    {id: 7, name: "..."},
    {id: 8, name: "..."}
]

My goal is to divide this array into two equal-length arrays and have different random data in each array every time the function is executed, not the same set of objects.

I attempted to achieve this using the following function:

function splitArr(data, part) {
    let list1 = [];
    let list2 = [];
    for(let i = 0; i < data.length ; i++) {
        let random = Math.floor(Math.random() * data.length);
        if(random % 2 === 0) {
            list1.push(data[i]);
        } else {
            list2.push(data[i]);
        }

    }
    return [list1, list2];
}

However, it is not guaranteed that the function will always return two arrays of equal length. Sometimes it returns arrays with 2 and 6 elements, which is not what I intended.

https://i.sstatic.net/QLzk2.png

Answer №1

To divide an array in half, first randomly shuffle the elements of the array.

Here is a function for shuffling an array, which can be found here:

function shuffle(a) {
    var j, x, i;
    for (i = a.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        x = a[i];
        a[i] = a[j];
        a[j] = x;
    }
    return a;
}

To split the shuffled array into two lists:

let list2 = shuffle([...data]); // spreading to avoid changing the original
let list1 = list2.splice(0, data.length >> 1); 

The shift operator >> is used to obtain the truncated half of the array length.

Answer №2

In my opinion, the most efficient and reliable approach would be utilizing native array methods in this scenario. I highly suggest implementing the slice method as demonstrated below:

function separateArray(data) {
  const arrayLength = data.length;

  const firstHalf = data.slice(0, arrayLength/2);
  const secondHalf = data.slice(arrayLength / 2, arrayLength);

  return [firstHalf, secondHalf];
}

This function provides a versatile solution that consistently yields two arrays of equal length. For special cases involving arrays with odd lengths, consider experimenting with Math.min() and Math.ceil.

Answer №3

To effortlessly achieve this task, consider utilizing randojs.com. The randoSequence function is particularly useful as it does not impact the original array. Afterwards, utilize the slice function to divide the arrays and employ the bitwise operator >> for handling arrays with an odd length.

function shuffleAndSplit(arr){
  var shuffled = randoSequence(arr);
  shuffled.forEach((item, i) => {shuffled[i] = item.value;});
  return [shuffled.slice(0, shuffled.length >> 1), shuffled.slice(shuffled.length >> 1)];
}

console.log(shuffleAndSplit(["a", "b", "c", "d", "e", "f", "g"]));
<script src="https://randojs.com/1.0.0.js"></script>

If you wish to simplify further while disregarding Internet Explorer compatibility issues, consider using the map function. Here's a variation of the previous code snippet that utilizes map:

function shuffleAndSplit(arr){
  var shuffled = randoSequence(arr).map(item => item.value);
  return [shuffled.slice(0, shuffled.length >> 1), shuffled.slice(shuffled.length >> 1)];
}

console.log(shuffleAndSplit(["a", "b", "c", "d", "e", "f", "g"]));
<script src="https://randojs.com/1.0.0.js"></script>

Answer №4

If you're looking to divide it into two separate parts, consider using the splice method.

This method takes two parameters (three if replacing elements): the starting index for splicing and the number of elements to remove. It will return the removed elements, effectively splitting your array in half. By removing elements from the original array, you'll end up with two arrays of equal length (especially when dealing with an even number of elements).

To add randomness to your array before splitting it, you can simply shuffle it beforehand. Below is an example leveraging a function from Jeff's answer:

/**
 * https://stackoverflow.com/a/6274381/5784924
 * Shuffles array in place. ES6 version
 * @param {Array} a items An array containing the items.
 */
function shuffle(a) {
    for (let i = a.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [a[i], a[j]] = [a[j], a[i]];
    }
    return a;
}

let persons = shuffle([
    {id: 1, name: "..."},
    {id: 2, name: "..."},
    {id: 3, name: "..."},
    {id: 4, name: "..."},
    {id: 5, name: "..."},
    {id: 6, name: "..."},
    {id: 7, name: "..."},
    {id: 8, name: "..."}
]);

let firstArray = persons.splice(0, persons.length / 2);
console.log(firstArray.map((item) => item.id), persons.map((item) => item.id));

Answer №5

the issue with the current method is as follows:

if(random % 2 === 0) {
    list1.push(data[i]);
} else {
    list2.push(data[i]);
}

attempting to insert into a random array without considering if both arrays are of equal length poses a problem (maintaining true randomness will be difficult).

it would be more effective to randomly insert items into each array during every iteration.

let persons = [
    {id: 1, name: "..."},
    {id: 2, name: "..."},
    {id: 3, name: "..."},
    {id: 4, name: "..."},
    {id: 5, name: "..."},
    {id: 6, name: "..."},
    {id: 7, name: "..."},
    {id: 8, name: "..."}
]
function splitArr(data, part) {
    let list1 = [];
    let list2 = [];
    let isPair = false;
    
    while(data.length > 0){
      const randomEntry = Math.floor(Math.random() * data.length);
      const arrayToPush = isPair?list1:list2;
      arrayToPush.push(data[randomEntry]);
      data.splice(randomEntry, 1);
      isPair = !isPair;
    }
    console.log(list1.length, list2.length)
    return [list1, list2];
}

splitArr(persons)

Answer №6

Would you find this solution beneficial?


function shuffleArray(data, numberOfDecks) {
  data = data.slice();
  const decks = [];
  let i = 0;
  while (data.length) {
    if (!Array.isArray(decks[i])) decks[i] = [];
    decks[i].push(data.splice(Math.random()*data.length, 1)[0]);
    i = (i+1) % numberOfDecks;
  }
  return decks;
}

shuffleArray(players, 4) // specifying 4 for four decks

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Efficiently handle user authentication for various user types in express.js with the help of passport.js

Struggling to effectively manage user states using Passport.js in Express.js 4.x. I currently have three different user collections stored in my mongodb database: 1. Member (with a profile page) 2. Operator (access to a dashboard) 3. Admin (backend privi ...

Tips for setting up your Webpack configuration

I'm having trouble compiling sass and jade. Although I found an option for sass, it only compiles at startup and doesn't work properly. Here are the commands I've tried: webpack-dev-server --watch-poll webpack-dev-server --watch webpack ...

Loading an empty CSS file in Node.js

Just starting out with node.js, and I could really use some help with a small css and image issue that I'm facing. I've streamlined my html and .js for clarity. Despite trying everything, the css and image just won't load. My form and server ...

I found myself in a bit of a predicament as I tried to transition a petite

Recently, I've been working on a small project that is built using pure HTML, CSS, and JavaScript. As I am delving into the realm of Vue.js, I decided to challenge myself by migrating this project to Vue.js. Here is how it currently functions with Ja ...

Cypress and Cucumber collaborate to reinitialize the requests within Next Js

In my upcoming project with Next.js, I am utilizing Cypress for testing a specific page. The objective is to validate two scenarios: 1. Successful outcome and 2. Error handling when a user encounters an issue. Before(() => { return void cy.server() ...

The MediaStream Recording API is failing to capture video from the canvas element

I have been attempting to record and download video from a canvas element using the official MediaStream Recording API <!DOCTYPE html> <html> <body> <h1>Testing mediaRecorder</h1> <canvas id="myCanvas" w ...

Is it not possible to update the datepicker parameter when another datepicker is changed?

I'm facing an issue with two datepickers in a form. When the user selects a date in the first datepicker, I need the min and max date of the second datepicker to be updated (one year from the selection). However, the problem is that the min and max da ...

Pausing and resuming WebRTC streams

Currently, I am exploring the integration of WebRTC in developing a web application that requires the ability to pause and resume video/audio streams based on certain events. While I attempted to use getTracks()[0].stop(), I am uncertain about how to res ...

Grunt tip: Converting jshint results to HTML format

I've set up jshint to run with grunt successfully, but now I'm looking to have the output in HTML format. Below is my grunt configuration: module.exports = function(grunt) { // Project configuration. grunt.initConfig({ jshint: { ...

Receiving a null value when trying to access a textview from an array of textviews

I defined five textviews with the names textview1 to textview5. I then created an array of textviews as shown below:- TextView tvArr[] = new TextView[] { textview1, textview2, textview3, textview4, textview5 }; However, when I try to use the setText met ...

Build a customizable digital clock script with Javascript/jQuery that displays the time in 24-hour format

Currently seeking a 24-hour format digital clock script in JavaScript/jQuery that also includes the date. The unique feature of this clock is that it will display images as its numbers and date, making for a visually appealing design. Additionally, I wou ...

Customize jQuery Tabs Styling

There was a time when I customized something in the CSS, marking it as important. It seemed fine back then. However, now it's causing an issue by changing the hover over color of active and inactive tabs (Yellow Arrow) to black. I really need to rev ...

Accessing Data from the Wikipedia API

After receiving a JSON response with the following structure: { "batchcomplete": "", "query": { "pages": { "97646": { "pageid": 97646, "ns": 0, "title": "Die Hard", "extract": "Die Hard is a 1988 ...

Issue with React Ref: Invariant Violation when trying to addComponentAsRefTo

I'm encountering an issue while attempting to add a ref to a React component. The error message I'm seeing is as follows: invariant.js:39Uncaught Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding ...

Alert: Debugger now supports asynchronous stack traces in Node.js

I am currently facing an issue while trying to insert a document into my MongoDB collection. When I execute the program in the VS-Code IDE, I encounter the following error message: << C:\Program Files (x86)\nodejs\node.exe .\DBOp ...

How to dynamically update form select options using Zend Framework 2 (2.3) and AJAX

I'm facing an issue with concatenating 3 dynamic selects - state, country, city - using an ajax request. It seems more complex without zf2! The function works fine when $idState is manually set within stateCountryCityAction (e.g. $idState = 1;), but d ...

Generating custom images and positioning them randomly inside a designated div

I found this code snippet on StackOverflow and it got me thinking - how can I modify it to display multiple different images instead of repeating the same image? $(document).ready(function(){ var ticket="<div class='ticket'><img src=&ap ...

PHP code searching for an array within a loop

Consider the array $diff provided below. a, a, a, a, b, b, b, a, a, b, b, b, a, a, a, b A denotes a single value within $diff. B represents an array within $diff. We need to tally occurrences of A if it appears more than twice consecutively and is not p ...

What is the best method to prevent next.js components from overlapping one another?

I recently created a website using next.js and noticed an issue in my index.js file. There is a div that houses the main components of the site: class Page extends Component { render() { return ( <div className={styles.container}> ...

Error loading GLTF file

I'm having trouble displaying a GLTF model using three.js. If someone could help me identify the issue in my code, I would greatly appreciate it. import {GLTFLoader} from "./GLTFLoader.js"; var scene = new THREE.Scene(); ...