I have a data set that looks like this:
[
{
ProductID: 1,
ProductName: 'MyProduct',
Description: '.. some text here ..',
UnwantedData: 'garbage here'
},
{
ProductID: 2,
ProductName: 'MyOtherProduct',
Description: '.. some text here ..',
UnwantedData: 'garbage herAe',
GarbageField: '.. lorem ipsum ..'
}
]
I also have a reference array that looks like this:
[
{
name: 'ProductId',
map_to: 'item_id',
},
{
name: 'ProductName',
map_to: 'item_name',
},
{
name: 'Description',
map_to: 'description',
},
]
What I want to do is use that reference array to basically drop the "unwanted" data (ie. the properties that aren't names in the reference array) and replace the keys with whatever it's supposed to be mapped to (ie. ProductId->item_id).
The resulting array should look like this:
[
{
item_id: 1,
item_name: 'MyProduct',
description: '.. some text here ..'
},
{
item_id: 2,
item_name: 'MyOtherProduct',
description: '.. some text here ..'
}
]
What I've done so far
Given that ref is the reference array and data is the list of products.
var only = _.map( ref, 'name' );
var products = [];
async.eachLimit( data, 20, function(item, cb) {
products.push( _.pick(item, only) );
cb();
}, function(err) {
// .. then I iterate over the products array and manually replace each property
// I haven't done this yet
});
This code should work, but it feels a little inefficient and I want to know if there's a better way in achieving the desired resulting array since I'm going to be storing these in MongoDB.
Can anyone shed some light here?
You can try for loops:
var result = [];
for(var i=0; i<data.length; ++i) {
result[i] = {};
for(var j=0; j<ref.length; ++j)
result[i][ref[j].map_to] = data[i][ref[j].name];
}
var data = [
{
ProductID: 1,
ProductName: 'MyProduct',
Description: '.. some text here ..',
UnwantedData: 'garbage here'
}, {
ProductID: 2,
ProductName: 'MyOtherProduct',
Description: '.. some text here ..',
UnwantedData: 'garbage herAe',
GarbageField: '.. lorem ipsum ..'
}
];
var ref = [
{
name: 'ProductID',
map_to: 'item_id',
}, {
name: 'ProductName',
map_to: 'item_name',
}, {
name: 'Description',
map_to: 'description',
},
];
var result = [];
for(var i=0; i<data.length; ++i) {
result[i] = {};
for(var j=0; j<ref.length; ++j)
result[i][ref[j].map_to] = data[i][ref[j].name];
}
console.log(result);
Or, with ES5 array methods,
data.map(function(old) {
return ref.reduce(function(obj, assoc) {
obj[assoc.map_to] = old[assoc.name];
return obj;
}, {});
});
var data = [
{
ProductID: 1,
ProductName: 'MyProduct',
Description: '.. some text here ..',
UnwantedData: 'garbage here'
}, {
ProductID: 2,
ProductName: 'MyOtherProduct',
Description: '.. some text here ..',
UnwantedData: 'garbage herAe',
GarbageField: '.. lorem ipsum ..'
}
];
var ref = [
{
name: 'ProductID',
map_to: 'item_id',
}, {
name: 'ProductName',
map_to: 'item_name',
}, {
name: 'Description',
map_to: 'description',
},
];
console.log(data.map(function(old) {
return ref.reduce(function(obj, assoc) {
obj[assoc.map_to] = old[assoc.name];
return obj;
}, {});
}));
I usually find it easier to split objects into pairs with _.pairs, operate on the pairs, then turn them back into an object with _.object:
function goodPair(product_pair) {
var k = product_pair[0];
return refmap[k] != null;
}
function fixPair(product_pair) {
var k = product_pair[0];
var v = product_pair[1];
return [refmap[k], v];
}
function trimProduct(full_product) {
return _.object(_.pairs(full_product)
.filter(goodPair)
.map(fixPair));
}
console.log(data.map(trimProduct));
This way you can turn the entire transformation into one synchronous map over your product array.
Note that this is using a slightly simplified version of your ref here as refmap
var refmap = _.object(ref.map(function(r) {
return [r.name, r.map_to];
}));
// OR
var refmap = {
'ProductId': 'item_id',
'ProductName': 'item_name',
'Description': 'description',
};
I would use map() and transform() for this:
_.map(data, function(item) {
return _.transform(ref, function(result, r) {
result[r.map_to] = item[r.name];
}, {});
});
You're mapping your data to a new structure. Each new item is the result of transforming the ref item. The map_to key in the new object gets the name value in the original collection.
Related
I have an n levels deep nested array of tag objects with title and ID. What I'm trying to create is a an object with IDs as keys and values being an array describing the title-path to that ID.
I'm no master at recursion so my attempt below doesn't exactly provide the result I need.
Here's the original nested tag array:
const tags = [
{
title: 'Wood',
id: 'dkgkeixn',
tags: [
{
title: 'Material',
id: 'ewyherer'
},
{
title: 'Construction',
id: 'cchtfyjf'
}
]
},
{
title: 'Steel',
id: 'drftgycs',
tags: [
{
title: 'Surface',
id: 'sfkstewc',
tags: [
{
title: 'Polished',
id: 'vbraurff'
},
{
title: 'Coated',
id: 'sdusfgsf'
}
]
},
{
title: 'Quality',
id: 'zsasyewe'
}
]
}
]
The output I'm trying to get is this:
{
'dkgkeixn': ['Wood'],
'ewyherer': ['Wood', 'Material'],
'cchtfyjf': ['Wood', 'Construction'],
'drftgycs': ['Steel'],
'sfkstewc': ['Steel', 'Surface'],
'vbraurff': ['Steel', 'Surface', 'Polished'],
'sdusfgsf': ['Steel', 'Surface', 'Coated'],
'zsasyewe': ['Steel', 'Quality']
}
So I'm building this recursive function which is almost doing it's job, but I keep getting the wrong paths in my flat/key map:
function flatMap(tag, acc, pathBefore) {
if (!acc[tag.id]) acc[tag.id] = [...pathBefore];
acc[tag.id].push(tag.title);
if (tag.tags) {
pathBefore.push(tag.title)
tag.tags.forEach(el => flatMap(el, acc, pathBefore))
}
return acc
}
const keyMap = flatMap({ title: 'Root', id: 'root', tags}, {}, []);
console.log("keyMap", keyMap)
I'm trying to get the path until a tag with no tags and then set that path as value for the ID and then push the items 'own' title. But somehow the paths get messed up.
Check this, makePaths arguments are tags, result object and prefixed titles.
const makePaths = (tags, res = {}, prefix = []) => {
tags.forEach(tag => {
const values = [...prefix, tag.title];
Object.assign(res, { [tag.id]: values });
if (tag.tags) {
makePaths(tag.tags, res, values);
}
});
return res;
};
const tags = [
{
title: "Wood",
id: "dkgkeixn",
tags: [
{
title: "Material",
id: "ewyherer"
},
{
title: "Construction",
id: "cchtfyjf"
}
]
},
{
title: "Steel",
id: "drftgycs",
tags: [
{
title: "Surface",
id: "sfkstewc",
tags: [
{
title: "Polished",
id: "vbraurff"
},
{
title: "Coated",
id: "sdusfgsf"
}
]
},
{
title: "Quality",
id: "zsasyewe"
}
]
}
];
console.log(makePaths(tags));
I need to create a Graphql query that outputs data from two arrays of objects. The arrays are:
const authors = [
{
name: 'Robert Martin',
id: 'afa51ab0-344d-11e9-a414-719c6709cf3e',
born: 1952
},
{
name: 'Martin Fowler',
id: 'afa5b6f0-344d-11e9-a414-719c6709cf3e',
born: 1963
},
{
name: 'Fyodor Dostoevsky',
id: 'afa5b6f1-344d-11e9-a414-719c6709cf3e',
born: 1821
},
{
name: 'Joshua Kerievsky', // birthyear not known
id: 'afa5b6f2-344d-11e9-a414-719c6709cf3e'
},
{
name: 'Sandi Metz', // birthyear not known
id: 'afa5b6f3-344d-11e9-a414-719c6709cf3e'
}
];
And:
const books = [
{
title: 'Clean Code',
published: 2008,
author: 'Robert Martin',
id: 'afa5b6f4-344d-11e9-a414-719c6709cf3e',
genres: ['refactoring']
},
{
title: 'Agile software development',
published: 2002,
author: 'Robert Martin',
id: 'afa5b6f5-344d-11e9-a414-719c6709cf3e',
genres: ['agile', 'patterns', 'design']
},
{
title: 'Refactoring, edition 2',
published: 2018,
author: 'Martin Fowler',
id: 'afa5de00-344d-11e9-a414-719c6709cf3e',
genres: ['refactoring']
},
{
title: 'Refactoring, edition 3',
published: 2018,
author: 'Martin Fowler',
id: 'afa5de00-344d-11e9-a414-719c6709cf3e',
genres: ['refactoring']
},
{
title: 'Refactoring, edition 4',
published: 2018,
author: 'Martin Cowler',
id: 'afa5de00-344d-11e9-a414-719c6709cf3e',
genres: ['refactoring']
},
{
title: 'Refactoring to patterns',
published: 2008,
author: 'Joshua Kerievsky',
id: 'afa5de01-344d-11e9-a414-719c6709cf3e',
genres: ['refactoring', 'patterns']
},
{
title: 'Practical Object-Oriented Design, An Agile Primer Using
Ruby',
published: 2012,
author: 'Sandi Metz',
id: 'afa5de02-344d-11e9-a414-719c6709cf3e',
genres: ['refactoring', 'design']
},
{
title: 'Crime and punishment',
published: 1866,
author: 'Fyodor Dostoevsky',
id: 'afa5de03-344d-11e9-a414-719c6709cf3e',
genres: ['classic', 'crime']
},
{
title: 'The Demon ',
published: 1872,
author: 'Fyodor Dostoevsky',
id: 'afa5de04-344d-11e9-a414-719c6709cf3e',
genres: ['classic', 'revolution']
}
];
The desired output format for a query like this:
query {
allAuthors {
name
bookCount
}
}
is like so:
"data": {
"allAuthors": [
{
"name": "Robert Martin",
"bookCount": 2
},
{
"name": "Martin Fowler",
"bookCount": 1
},
{
"name": "Fyodor Dostoevsky",
"bookCount": 2
},
{
"name": "Joshua Kerievsky",
"bookCount": 1
},
{
"name": "Sandi Metz",
"bookCount": 1
}
]
}
I've found a way to count the amount of books for each author and output the data in the desired format (a good example of that here: Summarize count of occurrences in an array of objects with Array#reduce). However this approach ignores other fields in the data, such as "born" and "genres". If I was to expand the query like so:
query {
allAuthors {
name
bookCount
born
}
}
It wouldn't output anything for the field "born". What would be the smart way to create the query resolver? Spread operator? Reduce?
* EDIT *
My unnecessarily complicated solution for counting the books here:
const newBooks = books.reduce((acc, cv) => {
const arr = acc.filter(obj => {
return obj.author === cv.author;
});
if (arr.length === 0) {
acc.push({ name: cv.author, born: cv.born, bookCount: 1 });
} else {
arr[0].bookCount += 1;
}
return acc;
}, []);
const array = [];
books.forEach(book => {
const object = {
name: book.author
};
array.push(object);
return array;
});
const unique = array.map(a => a.name);
result = {};
for (var i = 0; i < unique.length; ++i) {
if (!result[unique[i]]) result[unique[i]] = 0;
++result[unique[i]];
}
const entries = Object.entries(result);
const finalAnswer = [];
entries.forEach(entry => {
const object = {
name: entry[0],
bookCount: entry[1]
};
finalAnswer.push(object);
return finalAnswer;
});
console.log(finalAnswer);
You could map the authors and use filter to get the bookCount for each author
const authors=[{name:'Robert Martin',id:'afa51ab0-344d-11e9-a414-719c6709cf3e',born:1952},{name:'Martin Fowler',id:'afa5b6f0-344d-11e9-a414-719c6709cf3e',born:1963},{name:'Fyodor Dostoevsky',id:'afa5b6f1-344d-11e9-a414-719c6709cf3e',born:1821},{name:'Joshua Kerievsky',id:'afa5b6f2-344d-11e9-a414-719c6709cf3e'},{name:'Sandi Metz',id:'afa5b6f3-344d-11e9-a414-719c6709cf3e'}],
books=[{title:'Clean Code',published:2008,author:'Robert Martin',id:'afa5b6f4-344d-11e9-a414-719c6709cf3e',genres:['refactoring']},{title:'Agile software development',published:2002,author:'Robert Martin',id:'afa5b6f5-344d-11e9-a414-719c6709cf3e',genres:['agile','patterns','design']},{title:'Refactoring, edition 2',published:2018,author:'Martin Fowler',id:'afa5de00-344d-11e9-a414-719c6709cf3e',genres:['refactoring']},{title:'Refactoring, edition 3',published:2018,author:'Martin Fowler',id:'afa5de00-344d-11e9-a414-719c6709cf3e',genres:['refactoring']},{title:'Refactoring, edition 4',published:2018,author:'Martin Cowler',id:'afa5de00-344d-11e9-a414-719c6709cf3e',genres:['refactoring']},{title:'Refactoring to patterns',published:2008,author:'Joshua Kerievsky',id:'afa5de01-344d-11e9-a414-719c6709cf3e',genres:['refactoring','patterns']},{title:'Practical Object-Oriented Design, An Agile Primer Using Ruby ',published:2012,author:'Sandi Metz',id:'afa5de02-344d-11e9-a414-719c6709cf3e',genres:['refactoring','design']},{title:'Crime and punishment',published:1866,author:'Fyodor Dostoevsky',id:'afa5de03-344d-11e9-a414-719c6709cf3e',genres:['classic','crime']},{title:'The Demon ',published:1872,author:'Fyodor Dostoevsky',id:'afa5de04-344d-11e9-a414-719c6709cf3e',genres:['classic','revolution']}];
const output = authors.map(({ born, name }) => {
const bookCount = books.filter(b => b.author === name).length;
return { name, born, bookCount }
})
console.log(output)
I think you can add a statement to your reducer function to add the desired fields. I added the single line, and annotated the rest of the method so you can see what's going on:
const newBooks = books.reduce((acc, cv) => {
// acc is an "accumulation" of the results so far.
// cv is the next item that hasn't been processed.
// Search for author in "accumulator" array acc. Put results in arr.
const arr = acc.filter(obj => {
return obj.author === cv.author;
});
if (arr.length === 0) {
// Haven't seen this author, yet. Add new item to "accumulator" array.
acc.push({ name: cv.author, born: cv.born, bookCount: 1 });
} else {
// This author already exists in "accumulator" array, referenced by arr[0].
// Update pre-existing item.
arr[0].bookCount += 1;
arr[0].born = cv.born; // <-- This is the new code that is required.
}
return acc;
}, []);
I have an issue with manipulating data in Javascript/jQuery and I could use some help.
I have an array of objects that lools like this:
var projects = [
{title:'project1'},
{title:'project2'},
{title:'project3'},
];
I have another array of objects that looks like this:
ganttEvents = [
{
text: 'some text',
start_date: '2018/06/13',
end_date: '2018/06/14',
id: '1',
readonly: true,
project: 'project1',
category: 'scoping',
}
{
text: 'some text2',
start_date: '2018/06/14',
end_date: '2018/06/15',
id: '1',
readonly: true,
project: 'project2',
category: 'scoping',
}
{
text: 'some text3',
start_date: '2018/06/15',
end_date: '2018/06/16',
id: '1',
readonly: true,
project: 'project2',
category: 'design',
}
{
text: 'some text4',
start_date: '2018/06/13',
end_date: '2018/06/14',
id: '1',
readonly: true,
project: 'project2',
category: 'scoping',
}
{
text: 'some text5',
start_date: '2018/06/14',
end_date: '2018/06/15',
id: '1',
readonly: true,
project: 'project3',
category: 'testing',
}
{
text: 'some text6',
start_date: '2018/06/15',
end_date: '2018/06/16',
id: '1',
readonly: true,
project: 'project3',
category: 'build',
}
];
The project field in the second object will always be one of the objects in the first array.
I then need to end up with an object that looks like this:
source: [
{
name: "project1", // a project defined in the projects array
desc: "scoping", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/13", // the start_date from the ganttEvents array of objects
from: "2018/06/14", // the end_date from the ganttEvents array of objects
desc: "some text", // the text from the ganttEvents array of objects
label: "some text", // the text from the ganttEvents array of objects
}
]
},
{
name: "project2", // a project defined in the projects array
desc: "scoping", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/14",
from: "2018/06/15",
desc: "some text2",
label: "some text2",
},
{
to: "2018/06/13",
from: "2018/06/14",
desc: "some text4",
label: "some text4",
},
]
},
{
name: "project3", // a project defined in the projects array
desc: "testing", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/14",
from: "2018/06/15",
desc: "some text5",
label: "some text5",
}
]
},
{
name: "project3", // a project defined in the projects array
desc: "build", // the category from the ganttEvents array of objects
values: [
{
to: "2018/06/15",
from: "2018/06/16",
desc: "some text6",
label: "some text6",
}
]
},
]
There may be several values at all stages for each project and there maybe projects with no events at all that need to be omitted from the source object.
Please can you assist?
Edit:
The background behind this is that I am pulling a list of events from a SharePoint list using SharePointPlus. This results in the ganttEvents array. I need to plug this in to the jQuery.Gantt library which requires the events to be formatted in a particular way.
jQuery.Gantt
I am sorry but i am relatively new to Javascript (Python programmer usually) I have tried different methods of doing this to no avail.
You can use reduce to group the array into an object. Use the concatenated values of project and category as the key. Use Object.values to convert the object into an array.
var ganttEvents = [{"text":"some text","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project1","category":"scoping"},{"text":"some text2","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text3","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project2","category":"design"},{"text":"some text4","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text5","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project3","category":"testing"},{"text":"some text6","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project3","category":"build"}];
var result = Object.values(ganttEvents.reduce((c, v) => {
let k = v.project + "-" + v.category;
c[k] = c[k] || {name: v.project,desc: v.category,values: []};
c[k].values.push({to: v.end_date,from: v.start_date,desc: v.text,label: v.text});
return c;
}, {}));
console.log(result);
Without Object.values(), you can loop using for
var ganttEvents = [{"text":"some text","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project1","category":"scoping"},{"text":"some text2","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text3","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project2","category":"design"},{"text":"some text4","start_date":"2018/06/13","end_date":"2018/06/14","id":"1","readonly":true,"project":"project2","category":"scoping"},{"text":"some text5","start_date":"2018/06/14","end_date":"2018/06/15","id":"1","readonly":true,"project":"project3","category":"testing"},{"text":"some text6","start_date":"2018/06/15","end_date":"2018/06/16","id":"1","readonly":true,"project":"project3","category":"build"}];
var temp = ganttEvents.reduce((c, v) => {
let k = v.project + "-" + v.category;
c[k] = c[k] || {name: v.project,desc: v.category,values: []};
c[k].values.push({to: v.end_date,from: v.start_date,desc: v.text,label: v.text});
return c;
}, {});
var result = [];
for (var key in temp) result.push(temp[key]);
console.log(result);
I'm certain this question is very common, but I can't seem to find a robust answer for my use case.
I have an Array of objects with nesting in two levels. Here is an example of the array:
let array = [
{ company: 'CompanyName1',
child: [
{ title: 'title1a',
baby: [
{ title: 'title1ab' },
{ title: 'title1abc' }
]
},
{ title: 'title2a',
baby: [
{ title: 'titleb2abcd' },
{ title: 'titleb2abcde' }
]
}
]
},
{ company: 'CompanyName2',
child: [
{ title: 'title2b',
baby: [
{ title: 'titleb3ab' },
{ title: 'titleb3abc' }
]
}
]
}
]
And this is my expected Array:
let newArray = [
{
company: 'companyName1',
child_title_0: 'title1a',
child_title_1: 'title1a',
child_baby_0: 'title1ab',
child_baby_1: 'title1abc',
child_baby_2: 'title1abcd',
child_baby_3: 'title1abcde',
},
{
company: 'companyName2',
child_title_0: 'title2b',
child_baby_0: 'titleb3ab',
child_baby_1: 'titleb3abc',
}
]
Basically I need to flatten each of the top level objects of the array. Since the nested objects have the same keys (follow a model, and are dynamic -- some items have 10 nested objects, some 0, etc.) I have to dynamically generate each of the new keys, possibly based in the index of the loops.
Any help -- direction is appreciated.
Thanks!
You can use the map function to return a manipulated version of each object in the array.
let results = [
{
company: 'CompanyName1',
child: [
{
title: 'title1a',
baby: [
{ title: 'title1ab' },
{ title: 'title1abc' }
]
},
{
title: 'title2a',
baby: [
{ title: 'titleb2abcd' },
{ title: 'titleb2abcde' }
]
}
]
},
{
company: 'CompanyName2',
child: [
{
title: 'title2b',
baby: [
{ title: 'titleb3ab' },
{ title: 'titleb3abc' }
]
}
]
}
];
let flattened = results.map(company => {
let childCount = 0, babyCount = 0;
company.child.forEach(child => {
company['child_title_'+childCount] = child.title;
child.baby.forEach(baby => {
company['child_baby_'+babyCount] = baby.title;
babyCount++;
});
childCount++;
});
delete company.child;
return company;
});
console.log(flattened);
I'm trying to write a function which would take in the following array,
var data = [
{
name: 'Josh',
description: 'some data about this guy',
sortOrder: 'Gold'
},
{
name: 'Bill',
description: 'some data about this guy',
sortOrder: 'Platinum'
},
{
name: 'Gary',
description: 'some data about this guy',
sortOrder: 'Platinum'
},
{
name: 'Phillip',
description: 'some data about this guy',
sortOrder: 'Platinum'
},
{
name: 'Bob',
description: 'some data about this guy',
sortOrder: 'Gold'
},
{
name: 'Barry',
description: 'some data about this guy',
sortOrder: 'Gold'
},
{
name: 'Joe',
description: 'some data about this guy',
sortOrder: 'Gold'
},
{
name: 'Ed',
description: 'some data about this guy',
sortOrder: 'Silver'
},
{
name: 'Baxter',
description: 'some data about this guy',
sortOrder: 'Platinum'
},
{
name: 'Patrick',
description: 'some data about this guy',
sortOrder: 'Silver'
},
{
name: 'Stepehn',
description: 'some data about this guy',
sortOrder: 'Silver'
}
];
and give me an array which looked like this:
[Platinum, Gold, Silver] <-- The order doesn't matter
So it would check all sortOrder values in the array and return an array containing one instance of each unique sortOrder.
Anything I've written so far keeps giving me multiple instances of each sortOrder.... Could anyone give me a hand?
I have access to the underscore.js library if that can be of any help.
This should work great (clean js):
var orders = [];
for (var i = 0; i < data.length; i++){
if (data[i].sortOrder && orders.indexOf(data[i].sortOrder) == -1){
orders.push(data[i].sortOrder);
}
}
Try this
var result = _.chain(data)
.pluck('sortOrder')
.uniq()
.value();
console.log(result);
Example
With underscore :
console.log(_.chain(data).pluck('sortOrder').uniq().value());
As the values are String we can go via an Object in vanilla JavaScript
var a = (function (arr) {
var i, o = {};
for (i = 0; i < arr.length; ++i)
o[arr[i].sortOrder] = true;
return Object.keys(o);
}(data));
Without using any other library:
var results = [];
for(var i = 0; i < data.length; ++i){
if(results.indexOf(data[i].sortOrder) < 0){
results.push(data[i].sortOrder);
}
}
The results variable would contain the list you want.
Lots of plain JS offerings, which are always good to compare with libraries. Consider using ES5's reduce:
var result = data.reduce(function(acc, val) {
if (acc.indexOf(val.sortOrder) == -1) acc.push(val.sortOrder);
return acc;
},[]);
I feel like I'd use a Set to ensure the sortOrder stays single-entry. You can use the spread operator to place it back into an Array if that's the data structure you need. You don't have to write a new function or a lot of logic to check if an entry exists this way, though you could wrap the whole thing in a function if it is something you need to reuse a lot.
const result = [...new Set(data.map(({ sortOrder }) => sortOrder))];
Or as a function:
const getAllSortOrders = (data) => [...new Set(data.map(({ sortOrder }) => sortOrder))];