0
\$\begingroup\$

I'm wondering if there is a nicer way to acomplish what I want:

I do have an array with object like that:

let data = [
 {val1: [1,2,3,4], val2:[6,7,8,9] }
]

What I want is an object like:

let limit = {
 minX: 1, maxX: 4, minY: 6, maxY: 9
};

My Code works but once more I'm wondering if there is a nicer and shorter way to achieve it? Here is my solution:

 determineMinxMax(data: any) {
 let limit = {minX: null, maxX: null, minY: null, maxY: null}
 limit.minX = Math.min(...data.map(item => Math.min(...item.val1)));
 limit.maxX = Math.max(...data.map(item => Math.max(...item.val1)));
 limit.minY = Math.min(...data.map(item => Math.min(...item.val2)));
 limit.maxY = Math.max(...data.map(item => Math.max(...item.val2)));
 return limit;
 }
asked Sep 24, 2021 at 10:13
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The original code looks more like traditional JS, it does not benefit from typing features provided by the TypeScript language.

The solution I suggest below is not necessarily shorter, but its main goal is to put the things in order using the TS style.

First of all, interfaces can be created to define the structures of the data and limit objects:

interface MyDataItem {
 val1: Array<number>;
 val2: Array<number>;
};
interface Limit {
 minX: number;
 maxX: number;
 minY: number;
 maxY: number;
};

To access the val1 and val2 properties generically, a type and respective constants can be defined:

type PropertyAccessor = (item: MyDataItem) => Array<number>;
const accessorX: PropertyAccessor = item => item.val1;
const accessorY: PropertyAccessor = item => item.val2;

Similarly, to access the min and max values, we can define dedicated mapping constants:

type ValueExtractor = (values: Array<number>) => number;
const extractorMin: ValueExtractor = values => Math.min(...values);
const extractorMax: ValueExtractor = values => Math.max(...values);

Now, the implementation of the determineMinMax function becomes very concise and does not include repetitive stuff:

const determineMinMax = (data: Array<MyDataItem>): Limit => ({
 minX: extractMinMax(data, accessorX, extractorMin),
 maxX: extractMinMax(data, accessorX, extractorMax),
 minY: extractMinMax(data, accessorY, extractorMin),
 maxY: extractMinMax(data, accessorY, extractorMax)
});

Finally, we need to implement the extractMinMax function, which contains the main calculation logic:

const extractMinMax = (data: Array<MyDataItem>, 
 propertyAccessor: PropertyAccessor, 
 minMaxExtractor: ValueExtractor): number =>
 data.map(propertyAccessor) ​// extract the array with the current property from data
 ​.map(minMaxExtractor) // find the min value of each property
 ​.reduce((prev: number, next: number) => minMaxExtractor([prev, next])); // find the min value among all min values

...and a test case checking the calculated value:

describe('Q268329', () => {
 ​it('should return expected value', () => {
 ​const data = [
 ​{val1: [1,2,3,4], val2:[6,7,8,9] }
 ​];
 ​const limit = determineMinMax(data);
 ​expect(limit).toEqual({
 ​minX: 1, maxX: 4, minY: 6, maxY: 9
 ​});
 ​});
});
answered Sep 26, 2021 at 8:29
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I noticed you are consistently using Array<T>. I only have limited experience with TypeScript, but in my limited experience, it seems that T[] is a more idiomatic way to write that. \$\endgroup\$ Commented Sep 26, 2021 at 12:02
  • \$\begingroup\$ @"Jörg W Mittag" There is no "idiomatic" way between Array and [], both are similar. It's simply a choice of coding style. \$\endgroup\$ Commented Sep 26, 2021 at 14:15

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.