how would you solve this: Update the transform function such that it works with n number elements and also same function works for string element ?
const input = [
[2,3,5],
[2,4],
[7,8,9]
];
/*Edit only the transform */
const transform = (input, callback) => {
return callback([input[0],input[1]]);
}
/*Edit code only above */
const output = transform(input, (elm1, elm2) => {
return elm1.concat(elm2);// should return [7,8,9,2,4,2,3,5]
});
const input2 = ["hello", "welcome", !];
const output2 = transform(input2, (elm) => {
return elm.toUppercase(); // should return HELLO WELCOME !
});
Thank you all
In my opinion you're not writing clear JavaScript code. Functional paradigms are your friend but units of work that aren't meaningful will only work against you. What benefit does your transform function provide, why is it better than calling the cb method directly on your data? Consider looking into es6 array functions like flatMap and reduce.
const input = [
[2,3,5],
[2,4],
[7,8,9]
]
console.log(input.reduceRight((acc,cur) => acc.concat(cur), []))
// [7, 8, 9, 2, 4, 2, 3, 5]
console.log(["hello", "world"].map(str => str.toUpperCase()).join(" "))
//"HELLO WORLD"
You would need to pass the whole array to your transform function.
For the first output => flat the arrays using flat(Infinity)
For the second output => 'merge' all array value using join and then apply toUpperCase to the whole string:
const input = [
[2,3,5],
[2,4],
[7,8,9]
];
const transform = (input, callback) => {
return callback(input);
}
const output = transform(input.reverse(), (elm1, elm2) => {
return elm1.concat(elm2); // should return [7,8,9,2,4,2,3,5]
});
console.log(output.flat(Infinity).filter(Boolean));
const input2 = ["hello", " welcome", " !"];
const output2 = transform(input2, (elm) => {
return elm.join('').toUpperCase(); // should return HELLO WELCOME !
});
console.log(output2);
Related
I need convert this object:
{
"en": "[\"En1\",\"En2\"]",
"de": "[\"De1\",\"De2\"]"
}
to:
[
{
"en": "En1",
"de": "De1"
},
{
"en": "En2",
"de": "De2"
}
]
Can you help me?
i tried as follows:
const obj = {
en: '["En1","En2"]',
de: '["De1","De2"]',
};
const result = Object.entries(obj).map(([key, value]) => ({
[key]: JSON.parse(value),
}));
console.log(result)
but this only returns me an array of objects and I don't know how to go ahead and create a new array with key-value matches.
const data = {
"en": "[\"En1\",\"En2\"]",
"de": "[\"De1\",\"De2\"]"
}
console.log(Object.values(Object.entries(data).reduce((a,[k,v])=>
(JSON.parse(v).forEach((e,i)=>(a[i]??={})[k]=e),a),{})))
You can separate your object into 2 arrays then combine them like this
const obj = {
en: '["En1","En2"]',
de: '["De1","De2"]',
};
// Convert to array, separate them by key
let en = JSON.parse(obj.en.split(','));
let de = JSON.parse(obj.de.split(','));
//then combine both arrays
const result = en.map((x,i) =>({
en:x,
de:de[i]
}))
console.log(result);
You can use a combination of Array#map and Array#reduce as follows. The number of items is not hard-corded, so this will work for any number of items:
const
input = { "en": "[\"En1\",\"En2\"]", "de": "[\"De1\",\"De2\"]"},
output = Object.entries(input)
.map(([key,vals]) => JSON.parse(vals).map(v => ({[key]:v})))
//..producing [[{"en":"En1"},{"en":"En2"}],.....]
.reduce(
(obj, values) =>
obj.length === 0 ?
values.map(v => v) : //initial result: [{"en":"En1"},{"en":"En2"}]
values.map((v,i) => ({...obj[i],...v})), //appends "de" prop to each element, ....
[]
);
console.log( output );
I've opted for a more imperative approach here. It appends objects to the returnArray array for each index of the parsed values array. If value matches idx + 1 (eg 'De1'.includes(1)), a key-value pair is initialized on the object at the current index of the returnArray array.
My answer relies on a lot of assumptions regarding the input. If the parsed string array elements are not in numerical order, or there are gaps in the values, eg De3, De1, De2, or De1, De6, the current solution doesn't account for it.
let returnArray = [];
Object.entries(obj).forEach(pair => {
let key = pair[0];
let values = JSON.parse(pair[1]);
values.forEach((_el, idx) => {
if (!returnArray[idx]) {
returnArray.push({});
}
let value = values[idx];
if (value.includes(idx + 1)) {
returnArray[idx][key] = values[idx];
}
});
});
const a1 = [{x:1}, {x:2}],
const a2 = [{y:1}, {y:2}]
I want to achieve final result as:
a = [{x:1,y:1}, {x:2,y:2}]
how do I do this by map method.
const a = a1.map((item, index) => {
return [a1[index], a2[index]];
});
const a1 = [{
x: 1
}, {
x: 2
}];
const a2 = [{
y: 1
}, {
y: 2
}];
(function(a1, a2) {
const ret = a1.map((e, i) => ({ ...e,
...a2[i]
}))
console.log(ret)
})(a1, a2);
I don't know why you want to use map function, maybe is better to use other array methods for better performance and readability. But in this case if you want to use map you can iterate one of the arrays and create for each element ("e") an object, adding to it the corresponding position/key in the other array and the current one. Something like this:
const a = a1.map((e, i) => ({...e, ...a2[i]}))
I need to wrap each element of an array, even elements of the children.
input:
var array = [
{"name":"name1"},
{"name":"name2"},
{"name":"name3", children : [{"id":"1"}]}];
Desired output:
var newArray = [
{elem : {"name":"name1"}},
{elem : {"name":"name2"}},
{elem : {"name":"name3", children : [{elem : {"id":"1"}}]}}];
I have done the following:
function insertKey(array){
for (var i = 0; i<array.length; i++){
tempItem = {elem : array[i]}
newarray.push(tempItem);
}
}
// Output:
newarray =
[{elem:{"name":"name1"}},
{elem:{"name":"name2"}},
{elem:{"name":"name3"}}]
But the problem comes when it contains children. I tried the below but its not working.
function insertKey(array){
for (var i = 0; i<array.length; i++){
tempItem = {elem : array[i]}
newarray.push(tempItem);
insertKey(array[i]);
}
}
Thanks in advance.
To do this for any level of nesting, we can use a fairly simple recursive approach:
const transform = (xs) =>
xs .map (({children, ...rest}) => ({
elem: {
...rest,
...(children ? {children: transform (children)} : {})
}
}))
But I think one level of abstraction improves this significantly. If we separate the bit that wraps a node in an {elem: ...} structure from the bit that recursively applies that, our code is both simpler and more reusable. Its concerns are better separated. So I would probably write it like this:
const mapDeep = (fn) => (xs) =>
xs .map (({children, ...rest}) => fn ({
...rest,
...(children ? {children: mapDeep (fn) (children)} : {})
}))
const data = [
{name:"name1"},
{name:"name2"},
{name:"name3", children : [
{id: "1"},
{id: "2", children: [ {foo: "bar"}, {foo: "baz"} ]}
]}
]
const wrapInElem = (node) => ({elem: node})
console .log (mapDeep (wrapInElem) (data))
And of course by passing only the function to mapDeep, we get a reusable function that does what you want:
const transform = mapDeep (wrapInElem)
// or, using an anonymous function instead
// const transform = mapDeep (node => ({elem: node}))
// ...
transform (data)
you can try iterating over each object of array and adding them to new array. That gives the output that you desire.
define the function as:
-
function f(array){
newArray=[]
for(i of array){
newArray.push({elem:i})
}
return newArray
}
var array = [
{"name":"name1"},
{"name":"name2"},
{"name":"name3", children : [{"id":"1"}]}];
newArray=f(array)
console.log(newArray)
Sounds like you want something like this:
function insertKey(array) {
const newarray = [];
for (let i = 0; i < array.length; i++) {
const tempItem = {elem : array[i]};
if (array[i].children) {
tempItem.children = array[i].children.map(child => ({elem: child}));
}
newarray.push(tempItem);
}
return newarray;
}
The new conditional maps each child and wraps it like you described. You'll use this like so:
const newarray = insertKey(array);
Edit: Note that this solution only works for one level of nesting. If you needed it to go deeper, your question (as stated) doesn't give us enough information to help, because we don't know the schema of the data that you're trying to wrap.
I have an array like this
let oldArray=[
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
]
if the type is the same, i want to concat the value.
The result I want is:
let newArray=[
{type:16,img:['1','2','3']},
{type:17,img:['4']}
]
I tried to used reduce function:
oldArray.reduce((acc,cur,idx,src)=>{
if(cur.type===a[idx+1].type){
cur.img.concat(a[idx+1].img);
acc.push(cur)
} else {
acc.push(a[idx+1])
}
return acc
},[])
It seems that there is an error
Can anyone help? Thanks.
Alternative to Bibberty's solution:flatMap is much clearer than reduce
let newArray = [...new Set(oldArray.map(e => e.type))]
.map(e => {
return {
type: e,
img: (oldArray.filter(i => i.type === e).map(x => x.img)).reduce((acc,cur,idx,src)=>{
let length=src.length
let tep=cur.concat(src[idx+1]);
src[idx+1]=tep
return src[idx=length-1]
},[])
}
});
console.log(newArray);
You can use reduce:
let oldArray = [{type: 16,img: ['1']},{type: 16,img: ['2']},{type: 16,img: ['3']},{type: 17,img: ['4']}];
let newArray = oldArray.reduce((acc, curr) => {
acc.some(({
type
}) => type == curr.type) ? acc.find(({
type
}) => type == curr.type).img.push(curr.img[0]) : acc.push(curr);
return acc;
}, []);
console.log(newArray);
We use a Set and then a map.
The Set is populate with the unique types by using a map to extract.
We wrap in [] to give us an array the we then re map to build our object back.
The map then rebuilds our objects and note the use of filter and map to get the img values from the original host array.
let oldArray=[
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
]
let newArray = [...new Set(oldArray.map(e => e.type))]
.map(e => {
return {
type: e,
img: oldArray.filter(i => i.type === e).flatMap(x => x.img)
}
});
console.log(newArray);
This solution is not a reduce but return result you are looking for is the same
let oldArray = [
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
];
const transitoryMap = new Map();
for (const item of oldArray) {
if (!transitoryMap.has(item.type)) {
transitoryMap.set(item.type, [item.img[0]])
} else {
const value = transitoryMap.get(item.type)
value.push(item.img[0])
transitoryMap.set(item.type, value)
}
}
const newArray = [];
for (const item of transitoryMap.keys()) {
newArray.push({type:item,img:transitoryMap.get(item)})
}
console.log(newArray)
Here is an example using reduce. I have added a tracker to keep track of type in the newArray.
let oldArray = [
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
];
oldArray.reduce((a,c)=>{
let index = a.tracker.indexOf(c.type);
if(index === -1) {
a.tracker.push(c.type);
a.newArray.push({...c, img:[...c.img]});
} else {
a.newArray[index].img.push(...c.img);
}
return a;
},{tracker:[],newArray:[]}).newArray;
You might want to consider breaking up the processing into separate simple steps, for example:
Create a flattened object with the appropriate data.
build a new array with the wanted structure.
This will not only keep your code simple, but will allow you to focus on what your code is actually doing instead of how it is doing the task.
var oldArray=[
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
]
flattenMyObject = (arr) =>
arr.reduce((accum, current) => {
!!accum[current.type] ? accum[current.type].push(...current.img) : accum[current.type] = current.img;
return accum;
}, {});
buildNewArray = (type) => {
return {type: type, img: flattenedObject[type] }
}
Object
.keys(flattenMyObject(oldArray))
.map(buildNewArray);
I have a nested array like this
array = [[1, 698],[32, 798],[69, 830],[95, 500]]
I want to have a function that return the result in this format
[
{
id: 1,
score: 698
},
{
id: 32,
score: 798
},
{
id: 69,
score:830
},
..... the rest of the array
]
I did use a for loop but with no success, and I have no idea on how to aproach the situation.
for(var i = 0; i <= array.lenght ; i++){
var obj={}
var res = []
res.push(array[i])
}
You can take the advantage of the power of the ES6 syntax:
var array = [
[1, 698],
[32, 798],
[69, 830],
[95, 500],
];
var res = array.map(([id, score]) => ({id, score}));
console.log(res);
You can use Array.prototype.map() with destructuring assignment:
const array = [[1, 698],[32, 798],[69, 830],[95, 500]];
const result = array.map(([id, score]) => ({id, score}));
console.log(result);
Use array.prototype.map, destructuring and shorthand object litteral:
var array = [[1, 698],[32, 798],[69, 830],[95, 500]];
var result = array.map(([id, score]) => ({id, score}));
console.log(result);
var sampleArray = [[1, 698],[32, 798],[69, 830],[95, 500]];
var finalJson = sampleArray.map(([id, score]) => ({id, score}));
// Final Result
console.log(finalJson);
first you need a function that takes a 2 element array and returns an object
const objBuilder = arr => return { id: arr[0], score: arr[1] }
you will want to add error handling, but thats the basic idea.
Next you want to iterate over the array of arrays transforming each value (2 element array) into an object. Thats called mapping over values, and js supports it natively
const arrayOfObjects = array.map(objBuilder)
more about map function here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
The answers from a number of people suggesting .map(([id, score]) => ({id, score})) are great. But if you have to do things like this often, you might want to write a reusable function to make this more declarative. For that, something like this might work:
const zipObject = names => values => names.reduce(
(obj, name, idx) => (obj[name] = values[idx], obj), {}
)
const array = [[1, 698], [32, 798], [69, 830], [95, 500]]
console.log(array.map(zipObject(['id', 'score'])))
Note that you could also extend this to
zipAllObjects = names => listsOfValues => listsOfValues.map(zipObject(names))
and just call
zipAllObjects(['id', 'score'])(array)