I have an array of object like this
let data =
[
{
text: 'label'
},
{
text: 'username'
},
{
text: 'category'
},
{
text: 'book'
},
{
text: 'john'
},
{
text: 'education'
},
{
text: 'car'
},
{
text: 'doe'
},
{
text: 'automotive'
},
{
text: 'shoes'
},
{
text: 'cena'
},
{
text: 'fashion'
},
]
and my expect array of objects
let result =
[
{
label: 'book',
username: 'john',
category: 'education'
},
{
label: 'car',
username: 'doe',
category: 'automotive'
},
{
label: 'shoes',
username: 'cena',
category: 'fashion'
},
]
Just a simple for loop is probably the clearest. Here storing each object in a temp variable to avoid having to access the end of the result array every iteration, and abstracting the size into a variable.
let data = [{ text: 'label' }, { text: 'username' }, { text: 'category' }, { text: 'book' }, { text: 'john' }, { text: 'education' }, { text: 'car' }, { text: 'doe' }, { text: 'automotive' }, { text: 'shoes' }, { text: 'cena' }, { text: 'fashion' },];
const size = 3;
const result = [];
for (let temp, i = size; i < data.length; i++) {
if (i % size === 0) {
result.push(temp = {});
}
temp[data[i % size].text] = data[i].text;
}
console.log(result)
How about a switch-case with a modulo % operator to check for the current key:
const transformData = (data) => {
let result = [];
let tmpObj = {};
data.forEach((element, idx) => {
switch (idx % 3) {
case 0:
tmpObj["label"] = element.text;
break;
case 1:
tmpObj["username"] = element.text;
break;
case 2:
result.push({ ...tmpObj,
category: element.text
});
tmpObj = {};
break;
default:
break;
}
});
return result;
};
console.log(transformData(getSampleData()));
function getSampleData() {
return [{
text: 'label'
},
{
text: 'username'
},
{
text: 'category'
},
{
text: 'book'
},
{
text: 'john'
},
{
text: 'education'
},
{
text: 'car'
},
{
text: 'doe'
},
{
text: 'automotive'
},
{
text: 'shoes'
},
{
text: 'cena'
},
{
text: 'fashion'
},
];
}
According to your data,the top 3 records are property name,others are data,so we can use Array.slice() to get the property names
Then we can use Array.reduce() to convert the left data
let keys = data.slice(0,3).map(v => v.text)
let result = data.slice(3).reduce((a,c,i) =>{
let key = keys[i%3]
if(i%keys.length ==0){
let obj = {}
obj[key] = c.text
a.push(obj)
}else{
a.at(-1)[key]=c.text
}
return a
},[])
console.log(result)
let data =
[
{
text: 'label'
},
{
text: 'username'
},
{
text: 'category'
},
{
text: 'book'
},
{
text: 'john'
},
{
text: 'education'
},
{
text: 'car'
},
{
text: 'doe'
},
{
text: 'automotive'
},
{
text: 'shoes'
},
{
text: 'cena'
},
{
text: 'fashion'
},
]
let keys = Object.values(data.slice(0,3)).map(v => v.text)
let result = data.slice(3).reduce((a,c,i) =>{
let key = keys[i%3]
if(i%keys.length ==0){
let obj = {}
obj[key] = c.text
a.push(obj)
}else{
a.at(-1)[key]=c.text
}
return a
},[])
console.log(result)
Related
I have this array and I created this function that return me the filtered array:
const result = [{
key: 'A',
title: 'titleA',
data: [{
name: 'miael',
id: 'id4',
},
{
name: 'top',
id: 'id2',
}
]
},
{
key: 'B',
title: 'titleB',
data: [{
name: 'mich1',
id: 'id12',
},
{
name: 'tomato',
id: 'id123',
}
]
},
]
const doSearch = (data) => result.filter(entry =>
entry.data.some(item =>
item.name
.toString()
.toLowerCase()
.includes(data.toString().toLowerCase().trim()),
),
);
console.log(doSearch('mich'));
This works, but it also returns results that do not contain the searched word 'mic'
if I search for mic, I expect this result:
[{
key: 'B',
title: 'titleB',
data: [{
name: 'mich1',
id: 'id12',
},
]
}],
what am I doing wrong?
A couple of changes should make this work the way you wish.
Turning doSearch into a function.
Adding a searchFor parameter to the doSearch() function and passing to the .includes() call.
Using Array.reduce() to create the output array. Items are only added if they include the searchFor value.
const input = [{ key: 'A', title: 'titleA', data: [{ name: 'miael', id: 'id4', }, { name: 'top', id: 'id2', } ] }, { key: 'B', title: 'titleB', data: [{ name: 'mich1', id: 'id12', }, { name: 'tomato', id: 'id123', } ] }, ]
const doSearch = (searchFor, arr) => arr.reduce((acc, { key, title, data }) => {
const filteredData = data.filter(({ name }) => {
return name.toLowerCase().includes(searchFor.toLowerCase())
});
if (filteredData.length > 0) {
acc.push({ key, title, data: filteredData });
}
return acc;
}, []);
console.log(doSearch('mic', input ));
You can keep your current logic and add a map with the same filter for entry.data:
const result = [{
key: 'A',
title: 'titleA',
data: [{
name: 'miael',
id: 'id4',
},
{
name: 'top',
id: 'id2',
}
]
},
{
key: 'B',
title: 'titleB',
data: [{
name: 'mich1',
id: 'id12',
},
{
name: 'tomato',
id: 'id123',
}
]
},
]
function nameFilter(item, data) {
return item.name
.toString()
.toLowerCase()
.includes(data.toString().toLowerCase().trim())
}
const doSearch = (data) => result.filter(entry =>
entry.data.some(item =>
nameFilter(item, data)
),
).map(entry => ({
...entry,
data: entry.data.filter(item => nameFilter(item, data))
}));
console.log(doSearch('mich'));
Here is what I have
[
{
typeProgramId: {
name: 'type1',
},
title: 'test1',
},
{
typeProgramId: {
name: 'type1',
},
subTypeProgramId: [{
name: 'sub1',
}],
title: 'test2',
},
{
typeProgramId: {
name: 'type2',
},
title: 'test3',
},
{
typeProgramId: {
name: 'type2',
},
subTypeProgramId: {
name: 'sub2',
},
title: 'test4',
}
]
First I want to group typeProgramId if the title have the same typeProgramId I want to push title into array by each typeProgramId but If the data have typeProgramId and subTypeProgram Id I want to group subtypeProgramId in typeProgramId too. if not empty subtypeProgramId I want to push it in array title inside subtypeProgram Id. I try to use lodash groupBy and many way but it still did not work.
Here is what I want
{
typeProgramId: [{
name: 'type1',
title: [
'test1',
],
subTypeProgramId: {
name: sub1,
title: [
'test2'
]
}
}, {
name: 'type2',
title: [
'test3',
],
subTypeProgramId: [{
name: sub1,
title: [
'test4'
]
}
}]
}
what I do now
let result = _.groupBy(getProgram, function(data) {
return data.typeProgramId
})
result = _.map(result, function(group, data) {
// I think in here I must groupBy subTypeProgramId again
// the data return all string not object after group
return {
typeProgramId: data,
titile: group,
}
})
Please check the below code. I have used reduce function of Array. It produces the expected result.
function updateMem(mem, prgIndex, val){
if(prgIndex < 0) {
mem.typeProgramId.push({});
prgIndex = mem.typeProgramId.length - 1;
}
mem.typeProgramId[prgIndex].name = val.typeProgramId.name;
if(val.subTypeProgramId){
mem.typeProgramId[prgIndex].subTypeProgramId = Object.assign({}, mem.typeProgramId[prgIndex].subTypeProgramId || {}, {"name" : val.subTypeProgramId.name, "title": []});
mem.typeProgramId[prgIndex].subTypeProgramId.title.push(val.title);
} else {
mem.typeProgramId[prgIndex].title = (mem.typeProgramId[prgIndex].title ? mem.typeProgramId[prgIndex].title : []);
mem.typeProgramId[prgIndex].title.push(val.title);
}
};
arr.reduce((mem, val) => {
var prgIndex = mem.typeProgramId.findIndex((p) => p.name === val.typeProgramId.name);
updateMem(mem, prgIndex, val);
return mem;
}, {typeProgramId: []});
I got an array like this:
rows: [
[
{ title: 'Test', value: 1 },
{ title: 'Test2', value: 2 },
{ title: 'Test3', value: 3 },
],
[
{ title: 'Test4', value: 4 },
{ title: 'Test5', value: 5 },
],
[
{ title: 'Test6', value: 6 },
{ title: 'Test7', value: 7 },
]
]
Now I'd like to unset the key value in each nested object.
At the moment I am doing:
rows.map(function(fields){
return fields.map(function(field){
field.value = '';
return field;
})
});
Do you see a better way to do this?
function deleteKeyFromObject(inputObject) {
for (let[currentObjectKey,currentObjectValue] of Object.entries(inputObject)) {
if (currentObjectKey === 'value') {
delete inputObject.value;
} else if (Array.isArray(currentObjectValue)) {
deleteObjectFromArray(currentObjectValue);
} else if (typeof currentObjectValue === 'object') {
deleteKeyFromObject(currentObjectValue);
}
}
;
}
function deleteObjectFromArray(inputArray) {
for (let currentIndex = 0; currentIndex < inputArray.length; currentIndex++) {
let currentElement = inputArray[currentIndex];
if (Array.isArray(currentElement)) {
deleteObjectFromArray(currentElement);
} else if (typeof currentElement === 'object') {
deleteKeyFromObject(currentElement);
}
}
;
}
var data1 = {
rows: [[{
title: 'Test',
value: 1
}, {
title: 'Test2',
value: 2
}, {
title: 'Test3',
value: 3
}, ], [{
title: 'Test4',
value: 4
}, {
title: 'Test5',
value: 5
}, ], [{
title: 'Test6',
value: 6
}, {
title: 'Test7',
value: 7
}, ]]
}
deleteKeyFromObject(data1);
console.log(data1);
Probably not modifying existing objects could be a better practice:
rows = rows.map(fields => {
return fields.map(field => {
return {...field, value: ''};
})
});
You can use delete to explicitly remove a property and its value. No map needed:
var ob = {foo:'bar',fizz:'buzz'};
console.log(ob); // Object { foo: "bar", fizz: "buzz" }
delete ob.fizz;
console.log(ob); // Object { foo: "bar" }
I have 2 arrays of objects
NOTE: status and original-language can't be set manually as they change all the time, these are custom fields. The slugs from fields make up all custom fields.
const items = [
{
name: 'Surviving the Game',
status: 'ffdb29ba075fcbc0b71295c31a13d64f',
original-language: 'b4ebbe06702794d1cf375274197267b2',
},
{
name: 'Some Movie',
status: 'cd53c082c6ca9e7d3ec66890e66c01f3',
original-language: '7a1cac74217747933bb3915888dea090',
},
];
const fields = [
{
slug: 'status',
options: [
{
name: 'Released',
id: 'ffdb29ba075fcbc0b71295c31a13d64f',
},
{
name: 'Upcoming',
id: 'cd53c082c6ca9e7d3ec66890e66c01f3',
},
],
},
{
slug: 'original-language',
options: [
{
name: 'de',
id: 'b4ebbe06702794d1cf375274197267b2',
},
{
name: 'en',
id: '7a1cac74217747933bb3915888dea090',
},
],
},
];
status and original-language in [items] have an id value which matches an option in the corresponding fields array.
I am trying to return a new array for [items] with the name from options with the matching id.
eg:
[
{
name: 'Surviving the Game',
status: 'Released',
original-language: 'de',
},
{
name: 'Some Movie',
status: 'Upcoming',
original-language: 'en',
},
];
How would I go about this with ES6/7?
I am not sure where to start
I would accomplish this by creating a lookup object that houses lookups for both your statuses and languages. You can then use this lookup object when mapping through your items.
var items = [
{
name: 'Surviving the Game',
status: 'ffdb29ba075fcbc0b71295c31a13d64f',
"original-language": 'b4ebbe06702794d1cf375274197267b2'
},
{
name: 'Some Movie',
status: 'cd53c082c6ca9e7d3ec66890e66c01f3',
"original-language": '7a1cac74217747933bb3915888dea090'
}
];
var fields = [
{
slug: 'status',
options: [
{
name: 'Released',
id: 'ffdb29ba075fcbc0b71295c31a13d64f'
},
{
name: 'Upcoming',
id: 'cd53c082c6ca9e7d3ec66890e66c01f3'
}
]
},
{
slug: 'original-language',
options: [
{
name: 'de',
id: 'b4ebbe06702794d1cf375274197267b2'
},
{
name: 'en',
id: '7a1cac74217747933bb3915888dea090'
}
]
}
];
const lookup = {};
fields.forEach(field => {
lookup[field.slug] = field.options.reduce((all, option) => ({
...all,
[option.id]: option.name
}), {})
});
const translatedItems = items.map(item => {
return Object.entries(item)
.reduce((all, [key, val]) => ({
...all,
[key]: lookup[key] ? lookup[key][val] : val
}),{});
});
console.log(translatedItems);
I'd define a function that obtains the value for a field, like so:
function valueForField(field, id) {
const field = fields.find((itemfields) => itemfields.slug === field);
if(!field) return null;
const option = field.options.find(option => option.id === id);
if(!option) return null;
return option.name;
}
This can then be used like so:
const newItems = items.map(item => {
const { name } = item;
const newItem = {name};
newItem["original-language"] = valueForField('original-language', item["original-language"]);
newItem.status = valueForField('status', item.status);
return newItem;
});
Use map to create a new array of objects having name, status and originalLanguage fields along with the find method to get the name from fields for every status identifier.
const items = [{
name: 'Surviving the Game',
status: 'ffdb29ba075fcbc0b71295c31a13d64f',
originalLanguage: 'b4ebbe06702794d1cf375274197267b2',
},
{
name: 'Some Movie',
status: 'cd53c082c6ca9e7d3ec66890e66c01f3',
originalLanguage: '7a1cac74217747933bb3915888dea090',
},
];
const fields = [{
slug: 'status',
options: [{
name: 'Released',
id: 'ffdb29ba075fcbc0b71295c31a13d64f',
},
{
name: 'Upcoming',
id: 'cd53c082c6ca9e7d3ec66890e66c01f3',
},
],
},
{
slug: 'original-language',
options: [{
name: 'de',
id: 'b4ebbe06702794d1cf375274197267b2',
},
{
name: 'en',
id: '7a1cac74217747933bb3915888dea090',
},
],
},
],
newArr = items.map(i => ({
name: i.name,
status: fields.find(f => f.slug == 'status').options.find(o => o.id == i.status).name,
originalLanguage: fields.find(f => f.slug == 'original-language').options.find(l => l.id == i.originalLanguage).name
}));
console.log(newArr);
I create a ticket using zendesk but I didn't know why this happens
here is node js code:
config.js
baseTicketObject: {
'comment': {
'body': null,
},
'requester': {
'name': null,
'email': null,
},
'custom_fields': [],
},
create ticket api
function createTicketObjectFromRequest(req) {
const requestBody = req.body;
console.log('requestBody', requestBody);
console.log('config.baseTicketObject', config.baseTicketObject);
const ticket = Object.assign(config.baseTicketObject, {});
//console.log('ticket', ticket);
const {
messageBody, email, name, customFields,
} = requestBody;
//console.log('ticket.custom_fields', ticket.custom_fields);
// Request must contain a name, email and body
ticket.requester.name = name;
ticket.requester.email = email;
ticket.comment.body = messageBody;
if (req.user && req.user.id) {
ticket.custom_fields.push(createCustomFieldObject(config.customFieldNameToZendeskFieldIdMapping['userId'], Number(req.user.id)));
}
Object.keys(config.customFieldNameToZendeskFieldIdMapping).forEach((fieldName) => {
if (config.customFieldNameToZendeskFieldIdMapping[fieldName] === config.customFieldNameToZendeskFieldIdMapping.userId) {
return;
}
//console.log('fieldName', fieldName);
const mappedCustomFieldId = config.customFieldNameToZendeskFieldIdMapping[fieldName];
if (mappedCustomFieldId) {
ticket.custom_fields.push(createCustomFieldObject(mappedCustomFieldId, !customFields[fieldName] ? '' : customFields[fieldName]));
}
});
return { ticket: ticket };
}
whenever I post a request the config.baseTicketObject will keep all items i pushed before like this
config.baseTicketObject { comment: { body: null },
requester: { name: null, email: null },
custom_fields: [] }
-------------------------------------
config.baseTicketObject { comment: { body: 'dgfhdgfhdgfh dgfhdfghdfg' },
requester: { name: 'test other', email: 'tranthiphuonghue96#yopmail.com' },
custom_fields:
[ { id: 360010481051, value: '' },
{ id: 360010510411, value: '' },
{ id: 360010406792, value: '' },
{ id: 360010511011, value: '' },
{ id: 360010511191, value: '' },
{ id: 360010920852, value: 'contact_support' } ] }
---------------------------------------------------------
config.baseTicketObject { comment: { body: 'dgfhdgfhdgfh dgfhdfghdfg' },
requester: { name: 'test other', email: 'tranthiphuonghue96#yopmail.com' },
custom_fields:
[ { id: 360010481051, value: '' },
{ id: 360010510411, value: '' },
{ id: 360010406792, value: '' },
{ id: 360010511011, value: '' },
{ id: 360010511191, value: '' },
{ id: 360010920852, value: 'contact_support' },
{ id: 360010481051, value: '' },
{ id: 360010510411, value: '' },
{ id: 360010406792, value: '' },
{ id: 360010511011, value: '' },
{ id: 360010511191, value: '' },
{ id: 360010920852, value: 'contact_support' } ] }
I don't know why the config.baseTicketObject like that, please help.
Reverse parameters order in Object.assing.
You have
Object.assign(config.baseTicketObject, {});
but should be
Object.assign({}, config.baseTicketObject);
Object.assign syntax
Object.assign(target, ...sources)
In your case
const ticket = Object.assign({}, config.baseTicketObject);
Edit:
Add
ticket.custom_fields = [];
after
const ticket = Object.assign({}, config.baseTicketObject);
because Object.assign create shallow copy, witch mean that ticket.custom_fields still holds reference to original array object from config.baseTicketObject.custom_fields