I have this object
{
Bamboo: 7,
Eucalipto: 1,
Frassino: 2,
Ulivo: 1
}
I want to trasform this object in an array of object
[
{
plantName: Bamboo,
quantity: 7
},
{
plantName: Eucalipto,
quantity: 1
},
{
plantName: Frassino,
quantity: 2
},
{
plantName: Ulivo,
quantity: 1
},
]
What have you tried so far? Here's what I might do.
const dataObject = { Bamboo: 7, Eucalipto: 1, Frassino: 2, Ulivo: 1 };
const dataArray = Object.keys( dataObject ).map( ( key ) => {
return { 'plantName': key, 'quantity': dataObject[key] };
} );
console.log( dataArray );
You can map over the entries of the object, creating a new object with each key-value pair.
let obj = { Bamboo: 7, Eucalipto: 1, Frassino: 2, Ulivo: 1 };
let res = Object.entries(obj).map(([plantName,quantity])=>({plantName, quantity}));
console.log(res);
As you can see there are many different ways of doing this. But here are the basic steps as I learned them when I was starting out.
Create an array.
Iterate over the object.
Create a new object, and assign the key of the input object to "plantName", and the value of the input object to "quantity".
Add that new object to an array.
Here's an old-school way of achieving this:
const obj = { Bamboo: 7, Eucalipto: 1, Frassino: 2, Ulivo: 1 };
// Create an array
const arr = [];
// Iterate over the object
for (const key in obj) {
// Create a new object assigning the key
// to `plantName`, and the value to `quantity`
const newObj = {
plantName: key,
quantity: obj[key]
};
// Add the new object to the array
arr.push(newObj);
}
// Et voila!
console.log(arr);
Once you understand the basic concepts then you can start to introduce more complex methods like Object.entries, and map, but if you're just starting out with JavaScript this is probably more than enough to help you understand the process.
Related
Having the following array:
const vegsAndFruits = [
{
"fruit_banana": 10,
"fruit_apple": 1,
"veg_tomato": 3,
"fruit_watermelon": 11
},
{
"veg_carrot": 3,
"veg_garlic": 11,
"veg_potato": 0,
"fruit_apricot": 22
},
{
"veg_eggplant": 2,
"veg_cabbage": 1,
"fruit_strawberry": 100,
"fruit_orange": 30
}
]
I want to filter it to return the same array but to keep only the properties that start with "fruit".
Expected output
const expectedOutput = [
{
"fruit_banana": 10,
"fruit_apple": 1,
"fruit_watermelon": 11
},
{
"fruit_apricot": 22
},
{
"fruit_strawberry": 100,
"fruit_orange": 30
}
]
My attempt
I thought the solution should come from mixing ramda's R.startsWith() and R.pickBy(). But the following doesn't work as I expected:
const R = require("ramda")
R.map(R.pickBy(R.startsWith(["fruit"])),vegsAndFruits)
which returns
// [ {}, {}, {} ]
What am I missing here?
The R.pickBy predicate is called with the value (1st) and key (2nd) parameters. Since you need the key, use R.nthArg to create a function that returns the 2nd param:
const { map, pickBy, pipe, nthArg, startsWith } = R
const fn = map(pickBy(pipe(
nthArg(1),
startsWith('fruit')
)))
const vegsAndFruits = [{"fruit_banana":10,"fruit_apple":1,"veg_tomato":3,"fruit_watermelon":11},{"veg_carrot":3,"veg_garlic":11,"veg_potato":0,"fruit_apricot":22},{"veg_eggplant":2,"veg_cabbage":1,"fruit_strawberry":100,"fruit_orange":30}]
const result = fn(vegsAndFruits)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
The pickby function takes two parameters, value and key.
You can run R.map(R.pickBy((_, key) => key.startsWith('fruit')),vegsAndFruits) to get the result you want.
Is there any operation in Javascript just like [x for x in array] in python?
For example, I'm using javascript to reading a json file where there're dozens of (key, value) pairs needed to be handled(or transformed into other format). And I thought working in this way is stupid:
let transformed = []
for (let key in json){
transformed = [ /* doing some transform*/ ]
}
Is there anything like:
let transformed = [
lambda function1(key), lambda function2(value) for key, value in json
]
Thanks in advance.
The rough equivalent of Python's list comprehension is Array.map:
const myArray = [1, 2, 3]
const transformed = myArray.map((item) => item + 1)
// [2, 3, 4]
But your example is not about an array, but about an Object with keys and values. In Python, this would be a dict, and you'd use a dict comprehension along the lines of {function1(key): function2(value) for key, value in my_dict.items()}.
In JavaScript, you can turn such an object into an array with Object.entries, then perform the map, and finally transform it back into an object using Object.fromEntries:
const myObject = { a: 1, b: 2 }
const transformed = Object.fromEntries(Object.entries(myObject)
.map(([key, value]) => [key + 'x', value + 1]))
// { ax: 2, bx: 3 }
Note that fromEntries is fairly new and you might need to add a polyfill for it.
You can use a code likes this. You must use a function that handle operation on current single item.
const words = ['hello', 'bird', 'table', 'football', 'pipe', 'code'];
const capWords = words.forEach(capitalize);
function capitalize(word, index, arr) {
arr[index] = word[0].toUpperCase() + word.substring(1);
}
console.log(words);
// Expected output:
// ["Hello", "Bird", "Table", "Football", "Pipe", "Code"]
First of all, javascript does NOT support Associative Arrays. If you are used to them in Python, PHP, and other languages you need to do a little workaround in JS to achieve the same functionality.
The most common way to simulate an associative array is using an object.
let testObject = {name: "Color", value: "Red"};
And then you push every object into an array so you end up with something like this:
let testArray = [{name: "Color", value: "Red"}, {name: "Color", value: "Blue"}];
Once you have this array consisting of objects, you can use map function to go through every object in the array and do whatever you want with it.
testArray.map((item, index) => {
console.log("The value of "+index+". item is: "item.value);
})
You can use Array.map() function. It work pretty like Array.forEach() function
const numbers = [1, 2, 3, 4, 5]
let newArray = numbers.map((element) => {
return element * 2
})
console.log(newArray) // excepted : [ 2, 4, 6, 8, 10 ]
It can be reduce using
const numbers = [1, 2, 3, 4, 5]
let newArray = numbers.map(element => element * 2)
console.log(newArray) // excepted : [ 2, 4, 6, 8, 10 ]
For more informations, you can this documentation https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/map
I have an array of objects and all of them have at least 1 other object with the same ID. I am trying to reduce this array to only return the object with the most recent date. An example array of what I'm dealing with:
var arrObj = [
{id: 1, startDate: 2019-10-09},
{id: 1, startDate: 2019-10-05},
{id: 1, startDate: 2019-09-30},
{id: 2, startDate: 2018-08-05},
{id: 2, startDate: 2018-09-05}
]
Output I am trying to achieve:
var newArrObj = [
{id: 1, startDate: 2019-10-09},
{id: 2, startDate: 2018-09-05}
]
I have found a lot of examples of reducing or removing duplicate objects by ID completely, but I can't seem to find an example of first identifying the objects with the same ID, then reducing by a second property. Unfortunately I keep finding myself creating a lot of nested for loops. Is there an elegant way to do this? I need to be able to do it in ES5 or earlier.
var uniqueIDs = [];
for (a in arrObj) {
if(uniqueIDs.indexOf(arrObj[a].id) != -1) {
uniqueIDs.push(arrObj[a].id);
}
}
var newArrObj = [];
for(b in uniqueIDs) {
var uniqueId = uniqueIDs[b];
var uniqueIdObjs = arrObj.filter(function(x) {
return x.id === uniqueId;
});
for(c in uniqueIdObjs) {
var objDate = uniqueIdObjs[c].startDate;
//This is where I get stuck
}
}
I'd go with your style of first filtering the IDs to uniques, because thats the easy part.
Then you can simply chain array function so extract the last date:
map over the unique IDs so that your returns create a new array at the end.
filter the original array to include only object with the ID we workin on now
sort the temporary array created with all objects of the same ID so that the mostrecent one would be first, and return the first element.
let finalResult = uniqueIDs.map( id => {
return arrayObj.filter( obj => obj.id === id )
.sort((a, b) => new Date(b.startDate) - new Date(a.startDate))[0];
Tada! finalResult is now and array containing only one object with the most recent date for every ID :)
You can sort the array by date, get an array of ids and dedupe it, then map the deduped array to replace them with actual objects from the sorted array, Array.find will return the first matching result :
var arrObj = [
{ id: 1, startDate: "2019-10-09" },
{ id: 1, startDate: "2019-10-05" },
{ id: 1, startDate: "2019-09-30" },
{ id: 2, startDate: "2018-08-05" },
{ id: 2, startDate: "2018-09-05" }
];
// Sort by date
var sorted = arrObj.sort((a, b) => new Date(b.startDate) - new Date(a.startDate));
// dedupe the array of ids
var ids = [...new Set(sorted.map(o => o.id))];
// replace the ids with original objects
var result = ids.map(id => sorted.find(o => o.id === id));
console.log(result);
I've got two arrays that have multiple objects
[
{
"name":"paul",
"employee_id":"8"
}
]
[
{
"years_at_school": 6,
"department":"Mathematics",
"e_id":"8"
}
]
How can I achieve the following with either ES6 or Lodash?
[
{
"name":"paul",
"employee_id":"8"
"data": {
"years_at_school": 6
"department":"Mathematics",
"e_id":"8"
}
}
]
I can merge but I'm not sure how to create a new child object and merge that in.
Code I've tried:
school_data = _.map(array1, function(obj) {
return _.merge(obj, _.find(array2, {employee_id: obj.e_id}))
})
This merges to a top level array like so (which is not what I want):
{
"name":"paul",
"employee_id":"8"
"years_at_school": 6
"department":"Mathematics",
"e_id":"8"
}
The connector between these two is "employee_id" and "e_id".
It's imperative that it's taken into account that they could be 1000 objects in each array, and that the only way to match these objects up is by "employee_id" and "e_id".
In order to match up employee_id and e_id you should iterate through the first array and create an object keyed to employee_id. Then you can iterate though the second array and add the data to the particular id in question. Here's an example with an extra item added to each array:
let arr1 = [
{
"name":"mark",
"employee_id":"6"
},
{
"name":"paul",
"employee_id":"8"
}
]
let arr2 = [
{
"years_at_school": 6,
"department":"Mathematics",
"e_id":"8"
},
{
"years_at_school": 12,
"department":"Arr",
"e_id":"6"
}
]
// empObj will be keyed to item.employee_id
let empObj = arr1.reduce((obj, item) => {
obj[item.employee_id] = item
return obj
}, {})
// now lookup up id and add data for each object in arr2
arr2.forEach(item=>
empObj[item.e_id].data = item
)
// The values of the object will be an array of your data
let merged = Object.values(empObj)
console.log(merged)
If you perform two nested O(n) loops (map+find), you'll end up with O(n^2) performance. A typical alternative is to create intermediate indexed structures so the whole thing is O(n). A functional approach with lodash:
const _ = require('lodash');
const dataByEmployeeId = _(array2).keyBy('e_id');
const result = array1.map(o => ({...o, data: dataByEmployeeId.get(o.employee_id)}));
Hope this help you:
var mainData = [{
name: "paul",
employee_id: "8"
}];
var secondaryData = [{
years_at_school: 6,
department: "Mathematics",
e_id: "8"
}];
var finalData = mainData.map(function(person, index) {
person.data = secondaryData[index];
return person;
});
Sorry, I've also fixed a missing coma in the second object and changed some other stuff.
With latest Ecmascript versions:
const mainData = [{
name: "paul",
employee_id: "8"
}];
const secondaryData = [{
years_at_school: 6,
department: "Mathematics",
e_id: "8"
}];
// Be careful with spread operator over objects.. it lacks of browser support yet! ..but works fine on latest Chrome version for example (69.0)
const finalData = mainData.map((person, index) => ({ ...person, data: secondaryData[index] }));
Your question suggests that both arrays will always have the same size. It also suggests that you want to put the contents of array2 within the field data of the elements with the same index in array1. If those assumptions are correct, then:
// Array that will receive the extra data
const teachers = [
{ name: "Paul", employee_id: 8 },
{ name: "Mariah", employee_id: 10 }
];
// Array with the additional data
const extraData = [
{ years_at_school: 6, department: "Mathematics", e_id: 8 },
{ years_at_school: 8, department: "Biology", e_id: 10 },
];
// Array.map will iterate through all indices, and gives both the
const merged = teachers.map((teacher, index) => Object.assign({ data: extraData[index] }, teacher));
However, if you want the data to be added to the employee with an "id" matching in both arrays, you need to do the following:
// Create a function to obtain the employee from an ID
const findEmployee = id => extraData.filter(entry => entry.e_id == id);
merged = teachers.map(teacher => {
const employeeData = findEmployee(teacher.employee_id);
if (employeeData.length === 0) {
// Employee not found
throw new Error("Data inconsistency");
}
if (employeeData.length > 1) {
// More than one employee found
throw new Error("Data inconsistency");
}
return Object.assign({ data: employeeData[0] }, teacher);
});
A slightly different approach just using vanilla js map with a loop to match the employee ids and add the data from the second array to the matching object from the first array. My guess is that the answer from #MarkMeyer is probably faster.
const arr1 = [{ "name": "paul", "employee_id": "8" }];
const arr2 = [{ "years_at_school": 6, "department": "Mathematics", "e_id": "8" }];
const results = arr1.map((obj1) => {
for (const obj2 of arr2) {
if (obj2.e_id === obj1.employee_id) {
obj1.data = obj2;
break;
}
}
return obj1;
});
console.log(results);
I'm learning to manipulate JSON data and I am stuck trying to figure out how to cajole the following JSON into what I want as shown below:
Any pointers to function/terms/concepts that I should learn for this sort of problem would be greatly appreciated! Thanks
JSON object
{
car: 1,
van: 5,
cat: 99999999999999999999999
}
Desired outcome:
items: [
{ "type": "car", "value": "1"},
{ "type": "van", "value": "5"},
{ "type": "cat", "value": "99999999999999999999999"}
]
You can use a combination of Object.entries and Array.prototype.map:
const obj = { car: 1, van: 5, cat: 99999999999999999999999 };
let list = Object.entries(obj) // [["car",1],["van",5],["cat",99999999999999999999999]]
.map(x => ({ type: x[0], value: x[1] }));
console.log(list);
Or, with some destructuring:
const obj = { car: 1, van: 5, cat: 99999999999999999999999 };
let list = Object.entries(obj)
.map(([type, value]) => ({ type, value }));
console.log(list);
The callback to map:
([type, value]) => ({ type, value })
Expects an array as parameter: [type, value]. The first value in that array is assigned to type, the second one to value.
Then we use a shorthand form to set these values in our returned object:
=> ({ type, value })
I'm a beginner. I tried to solve the problem and this is the best I can come up with, tested in Node.js 10.
const obj = {"car": 1, "van": 5, "cat": 999999}
const items = []
for (let key in obj) {
items.push({"type": key, "value": obj[key]})
}
console.log(items)
One thing I am slightly confused about is the difference between for..in vs for..of, I'm currently looking into it.
Object.keys will return:
['car', 'van', 'cat'];
On this array you can use Array's map function which creates a new array with the results of calling a provided function on every element in the calling array.
var a = {
car: 1,
van: 5,
cat: 99999999999999999999999
}
m = Object.keys(a).map((v)=>{
return {
type: v,
value: a[v]
}
})
console.log(m);
#GustavMahler hope you understand. To learn more about array functions you should look map, reduce and filter.
This one uses object.keys
let js = {car:1, van:5, cat:9999}
Object.keys(js).map( x => ({type: x, value: js[x] }) )
[ { type: 'car', value: 1 },
{ type: 'van', value: 5 },
{ type: 'cat', value: 9999 } ]