-2

I have an array of objects with a name and a value that looks like this (sorted by values):

var array = [ 
    { Name: "F", Value: 320 },
    { Name: "E", Value: 321 },
    { Name: "C", Value: 340 },
    { Name: "G", Value: 340 },
    { Name: "A", Value: 400 },
    { Name: "D", Value: 403 },
    { Name: "B", Value: 404 }
]

I want to combine objects with the same value plus a tolerance. Grouping can be done like this:

var groupedArray = Object.groupBy(array, e => e.Value ); // Is it possible to add a tolerance factor here?

This creates groups that have exactly the same values. But what I actually want is a grouping with a certain tolerance. So, if values ​​are just slightly larger than the previous value, they should still be included in the group. The result could then look like this:

{
  320: [{
    Name: "F",
    Value: 320
  }, {
    Name: "E",
    Value: 321
  }],
  340: [{
    Name: "C",
    Value: 340
  }, {
    Name: "G",
    Value: 340
  }],
  400: [{
    Name: "A",
    Value: 400
  }, {
    Name: "D",
    Value: 403
  }, {
    Name: "B",
    Value: 404
  }]
}

... so all values ​​with a tolerance of, for example, +5 are in one group. Is it possible to add such a tolerance factor?

6
  • 3
    Round the values? For example Object.groupBy(array, ({ Value }) => Math.floor(Value / 10) * 10) would give you three groups: 320 (to 329); 340 (to 349) and 400 (to 409). Commented Sep 2 at 15:10
  • Within the GroupBy, round the value to the nearest X: stackoverflow.com/a/1684207/519413 Commented Sep 2 at 15:10
  • I suspect you might be looking for k-means clustering. It takes a dataset and iteratively splits it into groups until the groups converge. You don't specify the tolerance. If you have values around 300 and values around 400 you'd expect to get two clusters for those. But if you really want a tolerance, say, 310 should go in another group, then k-means is probably not the correct tool. Commented Sep 2 at 15:23
  • "if values ​​are just slightly larger than the previous value, they should still be included in the group." This is not a rigorous description of what you want. "just slightly larger" is not very specific and allows for a lot of interpretation. Commented Sep 2 at 15:26
  • 1
    The examples aren't really good. You should provide output for elements with e.g. values 321, 320, 324, 328, 331. That's the interesting detail. What's the expected output. How many groups do you want, and where does the value for the key come from? Commented Sep 2 at 15:54

2 Answers 2

2

You could reduce the sorted array by having a look to the difference of each value and predecessor and keep the group if the difference is in a wanted delta/tolerance.

Finally build entries for a later object.

const
    tolerance = 5,
    array = [{ Name: "F", Value: 320 }, { Name: "E", Value: 321 }, { Name: "C", Value: 340 }, { Name: "G", Value: 340 }, { Name: "A", Value: 400 }, { Name: "D", Value: 403 }, { Name: "B", Value: 404 }],
    result = Object.fromEntries(array
        .reduce((r, o, i, a) => {
            if (!i || o.Value - a[i - 1].Value > tolerance) r.push([o]);
            else r.at(-1).push(o);
            return r;
        }, [])
        .map(a => [a[0].Value, a])
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

Comments

0

GroupBy does not support it directly. But this possible using good old loops.

const array = [ 
    { Name: "F", Value: 320 },
    { Name: "E", Value: 321 },
    { Name: "C", Value: 340 },
    { Name: "G", Value: 340 },
    { Name: "A", Value: 400 },
    { Name: "D", Value: 403 },
    { Name: "B", Value: 404 }
];

function groupWithTolerance(arr, tolerance) {
  const result = {};
  let currentKey = arr[0].Value;   
  result[currentKey] = [arr[0]];

  for (let i = 1; i < arr.length; i++) {
    const item = arr[i];
    if (item.Value - currentKey <= tolerance) {
      result[currentKey].push(item);
    } else {
      currentKey = item.Value;
      result[currentKey] = [item];
    }
  }

  return result;
}

console.log(groupWithTolerance(array, 5));

PS: Note that this is dependent on the order, because your output is also dependent on the order.
If you have values such as 320,324,328. Would you want 324 and 328 together or 320 and 324, or 320,324,328 together?

1 Comment

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.