Javascript: Creating a Summary Object from a Series of Detail Objects - javascript

I'm iterating over a bunch of objects that look like this:
var tests = [{ date: 1379082017487,
summary:
{'Item A': 2069,
'Item B': 8987,
'Item C': 1890
}},
{date: 1379082015968,
summary:
{'Item A': 1824,
'Item B': 6758,
'Item C': 3857
}}];
I need to combine the data into a single object with the same keys, and arrays containing the combined values:
{ date: [1379082017487, 1379082015968],
summary:
{ 'Item A': [2069, 1824],
'Item B': [8987, 6758],
'Item C': [1890, 3857]
}
}
My strategy thus far is to create a nested loop; iterate over the top-level objects and add their values to a 'date' array. Then iterate over the 'summary' object, pushing those values to an array representing each key. In the end, I'd add the arrays back together to form my single output object.
My brain freeze is on the inner array. It can have a varying number of keys ('Items'). While these keys will have the same names for all objects in any given run of the code, they can have different names between runs. The inner loop isn't producing an array (like [2069, 1824]).
So far I have:
var testDates = [];
var itemVals = [];
// iterate over the outer objects
for (var record = 0; record < tests.length; record++) {
testDates.push(tests[record].date); // this works fine
// iterate over the inner 'summary' object:
for (var itemName in tests[record]['summary']) {
// doesn't produce the appropriate array
itemVals.push([tests[record]['summary'][itemName]]);
}
}
Thanks for any advice!

I have written a sample code for your problem. Please try this and let me know if it work
var tests = [{
date: 1379082017487,
summary: {
'Item A': 2069,
'Item B': 8987,
'Item C': 1890
}
}, {
date: 1379082015968,
summary: {
'Item A': 1824,
'Item B': 6758,
'Item C': 3857
}
}];
var json = {
date: [],
summary: {}
};
for (var i = 0; i < tests.length; i++) {
var dateJSON = tests[i];
json.date.push(dateJSON.date);
for (var key in dateJSON.summary) {
if (dateJSON.summary.hasOwnProperty(key)) {
if (json.summary[key] == null) {
json.summary[key] = [];
}
json.summary[key].push(dateJSON.summary[key]);
}
}
}

Related

JavaScript Replacing Object in Array with ID Number

So I have a series of objects that are pulled from an API and inputted into an array, something like such:
array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 1, name: "Second", relationship: "Friend"}
]
The user is allowed to add and remove objects to the list freely (they will appear within a Vue.JS DataTable), and said user is allowed a maximum of 4 objects within the array (lets say 4 "friends")
How should I go about implementing a function that searches the existing array (say, if its populated from the API), and inputs the new object with the corresponding ID that is missing (so if the user deletes the object with the id 2, and adds another, it will search said array with objects, find the missing id 2 slot in the array, and input the object in its place)?
Previously I have gone about it via implement array.find() with conditionals to see if the array contains or does not contain the certain id value, however, it searches through each entry and can end up inserting the same object multiple times. Another method I haven't attempted yet would be having a separate map that contains ids, and then when a user removes an object, having it correspond with the map, and vice versa when adding.
Any suggestions? Thanks
Instead of an array, I'd keep an object in data. Have it keyed by id, like this:
let objects = {
0: { id: 0, name: 'name0', relationship: 'relationship0' },
1: { id: 1, name: 'name1', relationship: 'relationship1' },
}
Integer keys in modern JS will preserve insertion order, so you can think of this object as ordered. The API probably returns an array, so do this...
// in the method that fetches from the api
let arrayFromApi = [...];
this.objects = array.reduce((acc, obj) => {
acc[obj.id] = obj; // insertion order will be preserved
return acc;
}, {});
Your UI probably wants an array, so do this (refer to "array" in the markup):
computed: {
array() {
return Object.values(this.objects);
},
To create a new object, insert it in order, minding the available keys. Note this is a linear search, but with small numbers of objects this will be plenty fast
methods: {
// assumes maxId is const like 4 (or 40, but maybe not 400)
createObject(name, relationship) {
let object = { name, relationship };
for (let i=0; i< maxId; i++) {
if (!this.objects[i]) {
object.id = i;
this.objects[i] = object;
break;
}
}
try this,
let array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 4, name: "Second", relationship: "Friend"},
{id: 2, name: "Second", relationship: "Friend"},
]
const addItem = (item) => {
let prevId = -1
// this is unnecessary if your array is already sorted by id.
// in this example array ids are not sorted. e.g. 0, 4, 2
array.sort((a, b) => a.id - b.id)
//
array.forEach(ob => {
if(ob.id === prevId + 1) prevId++
else return;
})
item = {...item, id: prevId + 1 }
array.splice(prevId+1, 0, item)
}
addItem({name: "x", relationship: "y"})
addItem({name: "a", relationship: "b"})
addItem({name: "c", relationship: "d"})
console.log(array)
You can simply achieve this with the help of Array.find() method along with the Array.indexOf() and Array.splice().
Live Demo :
// Input array of objects (coming from API) and suppose user deleted 2nd id object from the array.
const arr = [
{id: 0, name: "First", relationship: "Friend" },
{id: 1, name: "Second", relationship: "Friend" },
{id: 3, name: "Fourth", relationship: "Friend" }
];
// find the objects next to missing object.
const res = arr.find((obj, index) => obj.id !== index);
// find the index where we have to input the new object.
const index = arr.indexOf(res);
// New object user want to insert
const newObj = {
id: index,
name: "Third",
relationship: "Friend"
}
// Insert the new object into an array at the missing position.
arr.splice(index, 0, newObj);
// Output
console.log(arr);

Sequelize multiple delete on multiple columns

I need to delete rows based on query of multiple columns, here is my code:
var destroyQuery = testArr.map(function(mc){
return {
id: mc.id,
text: mc.text
}
});
db.testModel.destroy({ where: destroyQuery }).then(function(dResponse){});
For deleting one record it works fine:
db.testModel.destroy({ where: {id: '123', text: 'abc'} }).then(function(dResponse){});
How can i delete multiple rows by querying multiple columns. Any help is appreciated.
Thanks
For your argument "mc" in function, you should use an array like given example below:
var kvArray = [{key: 1, value: 10},
{key: 2, value: 20},
{key: 3, value: 30}];
var reformattedArray = kvArray.map(function(obj) {
var rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map check this article. might be it solve your purpose.
I used this option, is fast and simple
var destroyQuery = testArr.map(function(mc){
return {
id: mc.id,
text: mc.text
}
});
db.testModel.destroy({
where:{
[Op.or]: destroyQuery
}
}).then(function(dResponse){});

How to prevent lodash mapKeys from reordering my array?

I'm using lodash mapKeys to take my array of objects and convert it to a mapped object using the id property. That's simple enough, but the problem is that it's sorting the new object by id.
For example if I had three objects in my array:
let myArray = [
{
id: 3,
name: 'Number Three'
},
{
id: 1,
name: 'Number One'
},
{
id: 2,
name: 'Number Two'
}
];
Then I map the keys by id:
_.mapKeys(myArray, 'id')
It returns the following:
{
1: {
id: 1,
name: 'Number One'
},
2: {
id: 2,
name: 'Number Two'
},
3: {
id: 3,
name: 'Number Three'
}
}
My server returns the array in a specific order, so I would like the objects to remain the same, so that when I loop over the object properties, they are in the correct order.
Is that possible with this method? If not, is there a possible alternative to achieve the results?
Use a Map because each item has a custom key (like objects), but the order of insertion will be the order of iteration (like arrays):
const myArray = [
{
id: 3,
name: 'Number Three'
},
{
id: 1,
name: 'Number One'
},
{
id: 2,
name: 'Number Two'
}
];
const map = myArray.reduce((map, item) => map.set(item.id, item), new Map());
map.forEach((item) => console.log(item));
As pointed out in the comments, looping over an object doesn't guarantee order. If you want an ordered list, you need an array.
However, you could apply the iterator pattern. In this pattern, it's up to you to decide what “next” element is. So, you could have a set with the objects (in order to get them in constant time) and an array to store the order. To iterate, you'd use the iterator.
This code could be used as example.
Hope it helps.
let myArray = [{
id: 3,
name: 'Number Three'
}, {
id: 1,
name: 'Number One'
}, {
id: 2,
name: 'Number Two'
}];
let myIterator = ((arr) => {
let mySet = _.mapKeys(arr, 'id'),
index = 0,
myOrder = _.map(arr, _.property('id'));
return {
getObjById: (id) => mySet[id],
next: () => mySet[myOrder[index++]],
hasNext: () => index < myOrder.length
};
})(myArray);
// Access elements by id in constant time.
console.log(myIterator.getObjById(1));
// Preserve the order that you got from your server.
while (myIterator.hasNext()) {
console.log(myIterator.next());
}
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script>
Like mentioned in the comments, the best would be to keep the object references both in an array to keep the order and in a hash to ease updating.
Backbone's collection (source) works like this. It keeps objects in an array (models), but automatically updates a hash (_byId) when adding and removing models (objects) or when a model's id changes.
Here's a simple implementation of the concept. You could make your own implementation or check for a collection lib.
// a little setup
var array = [];
var hash = {};
var addObject = function addObject(obj) {
hash[obj.id] = obj;
array.push(obj);
}
// Create/insert the objects once
addObject({ id: 3, name: 'Number Three' });
addObject({ id: 1, name: 'Number One' });
addObject({ id: 2, name: 'Number Two' });
// Easy access by id
console.log("by id with hash", hash['1']);
// updating is persistent with the object in the array
hash['1'].name += " test";
// keeps the original ordering
for (var i = 0; i < 3; ++i) {
console.log("iterating", i, array[i]);
}

How to include elements of an array in another array?

So for example I have a MAIN array with all the information I need:
$scope.songs = [
{ title: 'Reggae', url:"#/app/mworkouts", id: 1 },
{ title: 'Chill', url:"#/app/browse", id: 2 },
{ title: 'Dubstep', url:"#/app/search", id: 3 },
{ title: 'Indie', url:"#/app/search", id: 4 },
{ title: 'Rap', url:"#/app/mworkouts", id: 5 },
{ title: 'Cowbell', url:"#/app/mworkouts", id: 6 }
];
I want to put only certain objects into another array without typing in each of the objects so the end result will look like
$scope.array1 = [
{ title: 'Reggae', url:"#/app/mworkouts",id: 1 },
{ title: 'Cowbell', url:"#/app/mworkouts",id: 6 }
];
I have tried this with no luck:
$scope.array1 = [
{ $scope.songs[1] },
{ $scope.songs[6] }
];
I will have to do a bunch of these so typing in each object would take forever, is there any faster way to do this? Thanks in advance :)
You need to do something like this:
$scope.array1 = $scope.songs.filter(function (song) {
return (song.title == "Reggae" || song.title == "Cowbell");
});
Here, the filter function will give you a filtered new array to be replaced for the original scope value.
Or in simple way, using the array indices, you can use:
$scope.array1 = [ $scope.songs[0] , $scope.songs[5] ];
You need to remove the braces since it's already an object. Although the array index starts from 0 so change index value based on 0.
$scope.array1 = [
$scope.songs[0] ,
$scope.songs[5]
];

Populate array with objects attributes of an object literal

I have some cards defined as objects within an object, e.g:
var cards = {
s2: {suit: 4, rank: 2, name: '2 of spades'},
s3: {suit: 4, rank: 3, name: '3 of spades'},
//etc.
};
I need them to be within an object, not an array.
I then need to create an array of certain length and populate it with cards.
Something along these lines:
var cardDeck = [];
for (i=0; i < 52, i++){
cardDeck.push(???);
}
I tried to use for in loop and play with keys and even managed to push objects, but only {key} worked for me, unfortunately giving object containing only key value. How do I get whole objects pushed into cardDeck array?
you almost had, it, just loop through the objects by their keys, get each object from the key, and push it into the array
fiddle: https://jsfiddle.net/q3jaagcq/
var cards = {
s2: {suit: 4, rank: 2, name: '2 of spades'},
s3: {suit: 4, rank: 3, name: '3 of spades'},
//etc.
};
var cardDeck = [];
for (var key in cards) {
var card = cards[key];
cardDeck.push(card);
}
console.log(cardDeck);

Categories