Separate the array optimally using a series of functions

I need help finding an algorithm or library that can efficiently split an array between functions. My priority is getting the best possible split, so I don't mind the complexity as it's for a small dataset. Recursive checking should be sufficient.

For example, consider this array:

const list = [{gender: "female"}, {gender: "female"}, {gender: "female"}, {gender: "male"}]

If we use the special function:

specialFunc(list, [(val) => val === 'female', (val) => val === 'male']);

We should expect the output to be:

[
 [{gender: "female"}, {gender: "female"}, {gender: "female"}],
 [{gender: "male"}]
]

This represents the optimal split based on our criteria.

However, running the function with different parameters may yield a different result:

specialFunc(list, [(val) => !!val, (val) => val === 'male']);

In this case, the output would be the same as before.

"The best way possible" means minimizing the difference in array length and maximizing the number of records in each sub-array.

I've extensively searched npmjs and Github without success. Any assistance would be greatly appreciated!

Answer №1

From my perspective, I believe I have a grasp on the requirements outlined here. The main goal is to group items based on multiple predicate functions, allowing for various groupings due to multiple predicates possibly returning true for the same item. The aim is to identify a grouping that minimizes the differences in sizes of the resulting groups.

The provided examples are not particularly convincing to me, so let's consider a different scenario. If we have a list of items like [8, 6, 7, 5, 3, 0, 9], and three predicates: (n) => n < 7, (n) => n > 3, and (n) => n % 2 == 1, then as an example, the number 8 can only belong to the second group (as it's greater than 3 but not less than 7 and not odd). The 6 can be part of either the first or second group, while the 5 has flexibility across all groups, leading to a possible arrangement depicted below:

  8      6       7        5         3     0      9
[[1], [0, 1], [1, 2], [0, 1, 2], [0, 2], [0], [1, 2]]
  ^    ^  ^    ^  ^    ^  ^  ^    ^  ^    ^    ^  ^
  |    |  |    |  |    |  |  |    |  |    |    |  |
  |    +--|----|--|----+--|--|----+--|----+----|--|------> Group 0 (n => n < 7)
  |       |    |  |       |  |       |         |  |
  +-------+----+--|-------+--|-------|---------+--|------> Group 1 (n > 3)
                  |          |       |            |
                  +----------+-------+------------+------> Group 2 (n % 2 == 1)

Considering the combination possibilities according to the constraints, there could be 48 potential partitions. A sample of such partitions is shown below:

[
  [ [6, 5, 3, 0], [8, 7, 9], [] ], 
  [ [6, 5, 3, 0], [8, 7],    [9] ], 
  [ [6, 5, 0],    [8, 7, 9], [3] ], 
  [ [6, 5, 0],    [8, 7],    [3, 9] ], 
  // ... (42 rows omitted)  
  [ [0],          [8, 6, 9], [7, 5, 3] ], 
  [ [0],          [8, 6],    [7, 5, 3, 9] ]
]

To determine the most optimal partition with minimal size variations, we calculate the statistical variance by summing the squares of the distances of the values from their mean. For instance, considering [[6, 5, 3, 0], [8, 7, 9], []] with lengths 4, 3, and 0; this yields a variance of 8.667. In comparison, the second option has lengths 4, 2, and

1</code, resulting in a variance of <code>4.667
. Ultimately, the ideal solution would consist of 3, 2, and 2 with a variance of 0.667, as exemplified by [[6, 5, 0], [8, 7], [3, 9]]. It's worth noting that there may be several alternatives exhibiting similar behaviors, and the subsequent determination process primarily selects the initial favorable choice.

If the problem delineation aligns with your expectations, the code snippet below appears to effectively address the scenario at hand:

const range = (lo, hi) => Array .from ({length: hi - lo}, (_, i) => i + lo)

// Additional utility functions, etc.
// Code snippet truncated for brevity
// Final call to specialFunc function 

console .log (specialFunc (
  [8, 6, 7, 5, 3, 0, 9], 
  [n => n < 7, n => n > 3, n => n % 2 == 1]
)) //=> [[6, 5, 0], [8, 7], [3, 9]]
.as-console-wrapper {max-height: 100% !important; top: 0}

A detailed explanation of key utility functions and processes involved in the operation is also provided within the response for clarity and comprehension purposes.


1The standard deviation offers a more explicit interpretation, although its calculation essentially involves the square roots of variances, ensuring consistent ordering without necessitating actual root extractions.

Answer №2

function divideElements<T>(elements: T[], conditions: ((x: T) => boolean)[]) {
    let options = conditions.map(c => elements.filter(c));
    let groups = conditions.map((_, index) => ({ data: [] as T[], index }));
    let result: T[][] = [];
    while (options.reduce((sum, a) => sum + a.length, 0) > 0) {
        groups.sort((a, b) => a.data.length - b.data.length);
        let smallGroup = groups[0];
        const smallGroups = groups.filter(g => g.data.length === smallGroup.data.length);
        if (smallGroups.length > 1) {
            smallGroup = smallGroups[Math.floor(Math.random() * (smallGroups.length - 1))];
        }
        if (options[smallGroup.index].length === 0) {
            result.push(smallGroup.data);
            groups = groups.filter(x => x !== smallGroup);
            continue;
        }
        const item = options[smallGroup.index][0];
        options = options.map(x => x.filter(y => y !== item));
        smallGroup.data.push(item);
    }
    result = [...result, ...groups.map(x => x.data)];
    return result;
}

function accurateDivideElements<T>(elements: T[], conditions: ((x: T) => boolean)[], times: number) {
    const options: { data: T[][]; diff: number }[] = [];
    for (let i = 0; i < times; i++) {
        const res = divideElements(elements, conditions);
        let diffBetweenGroups = 0;
        const groupLengths = res.map(x => x.length);
        for (let i = 0; i < groupLengths.length; i++) {
            for (let j = 0; j < groupLengths.length; j++) {
                diffBetweenGroups += Math.abs(groupLengths[i] - groupLengths[j]);
            }
        }
        options.push({ data: res, diff: diffBetweenGroups });
    }
    return options.sort((a, b) => a.diff - b.diff)[0].data;
}

const elements = [{ gender: 'female' }, { gender: 'female' }, { gender: 'female' }, { gender: 'male' }];
const conditions = [(x: any) => !!x.gender, (x: any) => !!x.gender];
const result = accurateDivideElements(elements, conditions, 100);
const b = result;

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

Distinguishing between a hidden input containing an "empty string" and one that is "null" in Javascript and VB

While attempting to JSON deserialize a collection in VB, I encountered the following issue. Dim items = JsonConvert.DeserializeAnonymousType(Page.Request.Params("Items"), New List(Of ItemDto)) An error occurred during deserialization where the string "va ...

Creating a fresh instance of an Object from a Service that leverages the $resource

I have been enhancing my existing code to improve its functionality by creating two objects for interacting with a RESTful API. Before, I utilized $http to retrieve the data and return the promise. I would then add some actions using .then and repeat the ...

Display options in Material-UI autocomplete only upon clicking the icon

Is there a way to display the options list only when clicking on the arrow icon as opposed to the textfield itself? I have reviewed the documentations without success in finding a solution. Example ...

Is it possible to deactivate dynamic binding in Vue.js?

I'm curious if there's a way to disable dynamic binding for a specific instance of an attribute that I'm displaying. Imagine I have the following code, utilizing two-way binding: this.$children[0].$data.hits In this scenario, I have a vac ...

Start an HTML5 video inside an iframe by clicking on the play button on the parent page

My web page features a video in an iframe that can be changed by clicking on links within the page. I have added play and pause buttons on the main page to control playback of the videos within the iframe. On another page without an iframe, I successfully ...

The issue of Dojo AMD failing to load a custom module

Trying to develop a web application using the ArcGIS API, Dojo, and Flask. The goal is to create a "file uploads" dialog by defining it as its own module with the Dojo 1.7 AMD convention (i.e. "define"). Current file structure: \static home.js ...

Removing a specific object from a MongoDB array by its unique identifier

I'm currently developing an application that focuses on playlists. Utilizing MongoDB with mongoose, I am storing videos within each playlist using an array structure as demonstrated below: { _id: ObjectId("61ca1d0ddb66b3c5ff93df9c"), name: "Playli ...

Display the contents of a particular cell in a 2D array in php that has been imported from a .csv file

Here's the situation: I have this code where I want to extract a specific cell from my CSV file without using MySQL. if (($handle = fopen("ebbe.csv", "r")) !== FALSE) { # Set the parent multidimensional array key to 0. $nn = 0; while (($d ...

Error encountered when attempting to retrieve data from an API route using s3, resulting in an uncaught promise with the message "SyntaxError: Unexpected token < in JSON at position 0

I'm attempting to retrieve a JSON file from an S3 bucket. Here is the API route I'm using to fetch the json file: const {GetObjectCommand, S3Client} = require("@aws-sdk/client-s3"); const client = new S3Client() // Add opts to S3 if nee ...

Calculate the sum of an array element by adding its value to the values of its nested array elements

I'm struggling to wrap my head around this task. Let's say I have the following PHP array Array ( [0] => Array ( [cat_id] => 2 [parent_id] => 1 [Title] => Default Category ...

Update the array elements to produce smaller sub arrays containing just a single item

I have a constant called cartProducts: const cartProducts = props.cartSlice; It outputs an array with the following items: Array [ Object { "cartQuantity": 3, "product": "5f15d92ee520d44421ed8e9b", }, Object { "cartQuantity": 2, "pro ...

There was a TypeError that occurred because the object did not have the 'ajax' method available

When attempting to initialize the quoteResults Javascript function on my Wordpress site, I encounter the following error in my console: Uncaught TypeError: Object #<Object> has no method 'ajax' I have successfully utilized the code below ...

The search bar is visible on desktop screens and can be expanded on mobile devices

Check out my code snippet below. <style> #searchformfix { width: 50%; border-right: 1px solid #E5E5E5; border-left: 1px solid #E5E5E5; position: relative; background: #fff; height: 40px; display: inline-block; border: ...

Stopping a velocity.js animation once it has completed: is it possible?

For the pulsating effect I'm creating using velocity.js as a fallback for IE9, refer to box2 for CSS animation. If the mouse leaves the box before the animation is complete (wait until pulse expands and then move out), the pulsating element remains vi ...

AngularJS directive that offers dynamic functionality

Currently, I am working on dynamically inserting an ng-options directive within various <select> elements throughout my application. These elements have their own unique class names and other directives, such as ng-if, among others. <div ng-app=" ...

How to dismiss a JavaScript alert without refreshing the page in Codeigniter 3

I am currently working on building a form with validation using both JavaScript and Codeigniter 3.04. Here is the HTML code for my form: <form class="form-horizontal" method="POST" onsubmit="check()"> //code </form> My goal is to validate t ...

Unable to retrieve scripts upon returning to the main page of a Jquery website

Starting fresh with this post, I'm feeling incredibly frustrated and close to giving up on JQM completely. This shouldn't be so difficult. Here's my website structure: OUI/ index.php js/ pages/ images/ On the index.php page at http://loca ...

AngularJS - Issue with model not refreshing after asynchronous call completed

Seeking assistance with an issue in Angular: the select control is not initially choosing the correct value but updates on subsequent changes. I am new to Angular, and my HTML code looks like this: <select class="form-control" ng-model="job.SalutationI ...

Implementing a Search Box feature in React-leaflet version 3.1.0

Struggling to incorporate a searchbox feature into my react app. Encountering the error message "Attempted import error: 'MapControl' is not exported from 'react-leaflet'" with the latest version of react-leaflet. import { MapContainer, ...

To trigger a method in a VueJS parent component, one can utilize event listening

In my VueJS 2 project, there are a parent component and a child component. The parent component sends a property named items to the child component. Whenever the user clicks on a button within the child component, it emits a refresh event using this synta ...