Related
From API I get such a json:
{
"purposes": [
{
"id": 1,
"code": "for-calls"
},
{
"id": 2,
"code": "task-management"
},
{
"id": 3,
"code": "messenger"
}
],
"availabilities": [
{
"id": 1,
"code": "free"
},
{
"id": 2,
"code": "free-basic-plan"
},
{
"id": 3,
"code": "trial-version"
}
],
"ecosystems": [
{
"id": 1,
"code": "browse-widget"
},
{
"id": 2,
"code": "web-app"
},
{
"id": 3,
"code": "installation-on-your-server"
}
]
}
How do I iterate over this json to get a new array containing the field values 'code' from each element. As a result, there should be /catalog/filter/value_of_code in each element of the array.
const obj = {
"purposes": [
{
"id": 1,
"code": "for-calls"
},
{
"id": 2,
"code": "task-management"
},
{
"id": 3,
"code": "messenger"
}
],
"availabilities": [
{
"id": 1,
"code": "free"
},
{
"id": 2,
"code": "free-basic-plan"
},
{
"id": 3,
"code": "trial-version"
}
],
"ecosystems": [
{
"id": 1,
"code": "browse-widget"
},
{
"id": 2,
"code": "web-app"
},
{
"id": 3,
"code": "installation-on-your-server"
}
]
}
const arr = Object.values(obj).reduce((acc, e) => [...acc, ...e.map(o => `/catalog/filter/${o.code}`)] ,[]);
console.log( arr );
Lets say you are receiving this JSON object in serverResp object.
Now lets check if any catalogs are present in the object.
if(Object.keys(serverResp).length)
Next we shall iterate over the catalogs
Object.keys(serverResp).forEach((cat) => )
Each cat represents a catalog. Next we shall fetch array against each key inside our forloop
const catItems = serverResp[cat];
catItems will contain all the items of a particular catalog. Now lets iterate over each catItems to get the "code" value
catItems.forEach(item => console.log(item.code));
Final piece of code will look like below-
const outputArray = [];
if(Object.keys(serverResp).length) {
Object.keys(serverResp).forEach((cat)=> {
const catItems = serverResp[cat];
catItems.forEach(item =>
outputArray.push(`/catalog/filter${item.code}`));
});
}
console.log(outputArray);
For example: I have an array of objects like this:
let arrayOfObjects: [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
Now I want to replace or overwrite the array above with the same array, but including different values (same keys, different values):
let arrayOfObjects: [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
];
How can this be done in TypeScript?
Try this JS
let oneArray = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
let twoArray = [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
];
let newArray = Object.assign([], oneArray, twoArray);
console.log(newArray);
In TS
interface Data {
oneArray: array;
twoArray: array;
}
function merge(data: Data) {
return Object.assign([], data.oneArray, data.twoArray);
}
let user = {
oneArray: [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
],
twoArray: [
{ "id": 0, "name": "Not Available" },
{ "id": 1, "name": "Not Ready" },
{ "id": 2, "name": "Not Started" }
]
};
console.log(merge(user));
Sure :)
let arrayOfObjects = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
const newValues = ['Not Available', 'Not Ready', 'Not Started'];
newValues.forEach((value, i) => {
arrayOfObjects.find(o => o.id === i).name = value;
});
console.log(arrayOfObjects);
I wouldn't recommend this though: functional programming is awesome.
let arrayOfObjects = [
{ "id": 0, "name": "Available" },
{ "id": 1, "name": "Ready" },
{ "id": 2, "name": "Started" }
];
let names = ['Not Available', 'Not Ready', 'Not Started']
let result = arrayOfObjects.map((user, index) => ({ ...user, name: names[index] }))
console.log(result)
I have three arrays.
1. Existing viewers array - existingViewers
New viewers array - newViewers
Permitted Viewers array - permittedViewers
permittedViewers is used for rendering the drop-down. And I wish to filter the newViewers and existingViewers entries from the permittedViewers.
I am doing this as three steps. And I am afraid this is not the optimized way. Can someone suggest the ideal way of doing this?
The expected result is
[
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let existingViewers = [{
"viewerId": 1,
"name": "name1"
},
{
"viewerId": 2,
"name": "name2"
}
],
newViewers = [
{
"viewerId": 3,
"name": "name3"
}
],
permittedViewers = [{
"id": 1,
"name": "name1"
},
{
"id": 2,
"name": "name2"
},
{
"id": 3,
"name": "name3"
},
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let grouped = [...existingViewers, ...newViewers]
let viewerFilter = grouped.map(viewer => { return viewer.viewerId; });
let filteredPermittedViewers = permittedViewers.filter(viewer => !viewerFilter.includes(viewer.id));
console.log(filteredPermittedViewers)
I'd make a Set of the ids of the first two arrays, and then filter the third by whether the set includes the id. (Sets have O(1) lookup time)
let existingViewers=[{"viewerId":1,"name":"name1"},{"viewerId":2,"name":"name2"}],newViewers=[{"viewerId":3,"name":"name3"}],permittedViewers=[{"id":1,"name":"name1"},{"id":2,"name":"name2"},{"id":3,"name":"name3"},{"id":4,"name":"name4"},{"id":5,"name":"name5"},{"id":6,"name":"name6"}];
const ids = new Set([...existingViewers, ...newViewers].map(({ viewerId }) => viewerId));
const output = permittedViewers.filter(({ id }) => !ids.has(id));
console.log(output);
You can compress all three statements into a single statement -- just replace the variable name with the statement that creates it:
let existingViewers = [{
"viewerId": 1,
"name": "name1"
},
{
"viewerId": 2,
"name": "name2"
}
],
newViewers = [
{
"viewerId": 3,
"name": "name3"
}
],
permittedViewers = [{
"id": 1,
"name": "name1"
},
{
"id": 2,
"name": "name2"
},
{
"id": 3,
"name": "name3"
},
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let filteredPermittedViewers = permittedViewers.filter(viewer => ! [...existingViewers, ...newViewers].map(viewer => viewer.viewerId).includes(viewer.id));
console.log(filteredPermittedViewers)
In the following code. I am trying to get the id of a variant that matches the selected objects
const selected = [ { "id": 14 }, { "id": 95 } ]
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
}
]
function filterVaiant() {
return variants.filter( options => {
// return id 3 because it matches the selected objects
});
}
console.log(filterVaiant());
The filter function should return variant id:3 because it has the same option values as the selected option values.
follow up
const colors = require('colors');
const selected = [ { "id": 14 }, { "id": 95 }, { "id": 21 } ]
let selected_ids = selected.map(e=>e.id);
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
},
{
"id": 4,
"option_values": [ { "id": 14 }, { "id": 95, }, { "id": 21 } ]
}
]
let vID = variants.filter(e=> e.option_values.every(e=> selected_ids.indexOf(e.id) > -1));
console.log("answer:",vID) // Returns 3 and 4 but should only return 4
in this scenario vID is 3 and 4 but should only return 4 because it is the only one that matches the selections exactly.
You can use .filter and .every to achieve this like
const selected = [ { "id": 14 }, { "id": 95 } ];
var ids = selected.map(e=>e.id);
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
}
];
var o = variants.filter(e=> e.option_values.every(e=> ids.indexOf(e.id) > -1));
console.log(o)
What's happening here is, get all the selected ids in an array, then filter the variants array based on if every entry of option_values has all the entries as the selected ids.
For each object, check that all items in selected appear in option_values (ops alias) by checking that the length is equal, and using Array.every(), and Array.find():
const selected = [ { "id": 14 }, { "id": 95 } ]
const variants = [{"id":1,"option_values":[{"id":7},{"id":95}]},{"id":2,"option_values":[{"id":8},{"id":95}]},{"id":3,"option_values":[{"id":14},{"id":95}]}];
function filterVaiant() {
return variants.filter(({ option_values: ops }) => {
if (selected.length !== ops.length) return false;
return selected.every(({ id }) =>
ops.find((o) => id === o.id));
});
}
console.log(filterVaiant());
Using a Set to store the selected Id's to look up and Array#every in a filter
const selected = [ { "id": 14 }, { "id": 95 } ]
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
}
]
function filterVaiant(selected) {
let ids = new Set(selected.map(({id})=>id))
return variants.filter( o => o.option_values.every(({id})=>ids.has(id)));
}
console.log(filterVaiant(selected));
Another solution with map only indexof and join:
const selected = [ { "id": 14 }, { "id": 95 } ]
const variants = [
{
"id": 1,
"option_values": [ { "id": 7 }, { "id": 95, } ]
},
{
"id": 2,
"option_values": [ { "id": 8 }, { "id": 95, } ]
},
{
"id": 3,
"option_values": [ { "id": 14 }, { "id": 95, } ]
}
]
function filterVaiant(selected) {
return variants[variants.map(obj => obj.option_values).map(outterarray => outterarray.map(innerArray=>innerArray.id).join('-') ).indexOf(selected.map(eb=>eb.id).join('-'))];
}
console.log(filterVaiant(selected));
I want to build an new JSON from existing one. The source has sections and rubrics that I no longer need for a listing. The new object called 'items' should have an array of the items.
The final JSON should be sorted by attribute 'name' and look like
{
"items": [
{
"id": 10000006,
"name": "Boah"
},
{
"id": 10000013,
"name": "Gut"
},
{
"id": 10000003,
"name": "Ipsum"
},
{
"id": 10000001,
"name": "Lorem"
},
{
"id": 10000005,
"name": "Lorum"
},
{
"id": 10000004,
"name": "Name"
},
{
"id": 10000002,
"name": "Stet"
}
]
}
For building the new JSON I get this source:
{
"sections": [
{
"name": "FooBar",
"rubrics": [
{
"name": "Foo",
"items": [
{
"id": 10000001,
"name": "Lorem"
},
{
"id": 10000002,
"name": "Stet"
},
{
"id": 10000003,
"name": "Ipsum"
}
]
},
{
"name": "Bar",
"items": [
{
"id": 10000004,
"name": "Name"
},
{
"id": 10000005,
"name": "Lorum"
},
{
"id": 10000006,
"name": "Boah"
}
]
}
]
},
{
"name": "BlahBloob",
"rubrics": [
{
"name": "Bla",
"items": [
{
"id": 10000013,
"name": "Gut"
}
]
},
{
"name": "Bloob",
"items": [
{
"id": 10000014,
"name": "Name"
},
{
"id": 10000015,
"name": "Lorem"
}
]
}
]
}
]
}
What do you think? How can I do this with plain JavaScript or maybe TypeScript?
Thanks for reading and have time for my question. And thanks for reply in advance.
Here you go. You just need to iterate over each rubric of each section of your source to get the items. At the end, sort your list of items by items, and you're done.
This example uses ES6 syntax, but it's easy to convert it to ES5 if needed.
function extractItems(source) {
const items = [];
for (const section of source.sections) {
for (const rubric of section.rubrics) {
items.push(...rubric.items);
}
}
items.sort((a, b) => a.name.localeCompare(b.name));
return { items };
}
A more functional approach use map and reduce to pick the rubrics and merge them.
data.sections
.map(section => section.rubrics) // get rubrics
.reduce((a, b) => a.concat(b)) // merge rubrics
.map(rubric => rubric.items) // get items from each rubric
.reduce((a, b) => a.concat(b)) // merge items
.sort((a, b) => a.name.localeCompare(b.name)); // sort
function(oldObj) {
var newObj = {
"items": []
};
oldObj.sections.forEach(function(section) {
section.rubrics.forEach(function(rubric) {
rubric.items.forEach(function(item) {
newObj.items.push(item);
});
});
});
newObj.items = newObj.items.sort(function(a, b) {
if (a.name < b.name) { return -1; }
if (a.name > b.name) { return 1; }
return 0;
});
return newObj;
}
And simply use JSON.parse() and JSON.stringify() to convert JSON to and from objects.
It might help you
var data ={
"sections": [
{
"name": "FooBar",
"rubrics": [{"name": "Foo", "items": [{"id": 10000001,"name": "Lorem"}, {"id": 10000002,"name": "Stet"}, {"id": 10000003,"name": "Ipsum"}]
}, {
"name": "Bar",
"items": [{
"id": 10000004,
"name": "Name"
}, {
"id": 10000005,
"name": "Lorum"
}, {
"id": 10000006,
"name": "Boah"
}]
}]
}, {
"name": "BlahBloob",
"rubrics": [{
"name": "Bla",
"items": [{
"id": 10000013,
"name": "Gut"
}]
}, {
"name": "Bloob",
"items": [{
"id": 10000014,
"name": "Name"
}, {
"id": 10000015,
"name": "Lorem"
}]
}]
}]
};
var itemObj = {};
var itemArr = [];
var sections = data.sections;
for(var i=0;i<sections.length;i++)
{
for(var j=0;j<sections[i].rubrics.length;j++){
for(var k=0;k<sections[i].rubrics[j].items.length;k++){
var itemObj;
itemObj['id'] = sections[i].rubrics[j].items[k].id;
itemObj['name'] = sections[i].rubrics[j].items[k].name;
itemArr.push(itemObj);
}
}
}
var finalObj = {"items":itemArr};
console.log(finalObj);
JSFiddle