Most efficient way to search through an object and array locating match - javascript

i have 2 object/arrays:
var objA = {
Red Chair : "DC10291",
USBDongle : "USKI82322",
}
var arrayB = [
{
field: "Yellow Banana",
id: "Yellow Banana"
},
{
field: "Red Chair",
id: "Red Chair"
},
{
field: "Garden",
id: "Garden"
}
]
What i am trying to do is, that if a KEY from objA, e.g. Red Chair, is present in arrayB, then remove it from arrayB.
I have done this:
var arrayClone = _.cloneDeep(arrayB);
var removeThese = [];
Object.keys(arrayClone).forEach(function(p) {
removeThese.push(p)
});
removeThese.forEach(function(remove) {
arrayB.forEach(function(item) {
if(item.id === remove) {
delete objA[remove];
}
});
});
The above works as expected, however is this the most effieicnt? Reasone i ask is because looping throuhg and array within an array loop doesnt feel the best practice? And will have performance impact

You can simply filter it, like this
_.filter(arrayB, obj => !objA.hasOwnProperty(obj.field))
// [ { field: 'Yellow Banana', id: 'Yellow Banana' },
// { field: 'Garden', id: 'Garden' } ]
This uses ES2015's Arrow function syntax. You can write the same with a normal function like this
arrayB.filter(function(obj) {
return !objA.hasOwnProperty(obj.field);
});
// [ { field: 'Yellow Banana', id: 'Yellow Banana' },
// { field: 'Garden', id: 'Garden' } ]
We are basically filtering out all the objects whose field value is a key in objA.

If you would like to keep the original arrayB and get a reduced version of it according to your condition then Array.prototype.reduce() does that with O(n) time complexity. However if you would like to perform this operation in place then Array.prototype.reduceRight() does that with O(n) time complexity.
var objA = {
"Red Chair" : "DC10291",
"USBDongle" : "USKI82322",
},
arrayB = [
{
field: "Yellow Banana",
id: "Yellow Banana"
},
{
field: "Red Chair",
id: "Red Chair"
},
{
field: "Garden",
id: "Garden"
}
],
arrayC = arrayB.reduce((p,c) => !objA[c.field] ? p.concat(c) : p, []);
console.log(arrayC);
arrayB.reduceRight((p,c,i,a) => (p[c.field] && a.splice(i,1),p),objA);
console.log(arrayB);

Related

How do I incorporate the index of an array while defining a property of said array within a class in JavaScript?

Sorry if the title makes no sense.. let me explain
Say I have the following 2d array.. the first array representing ice cream and the second representing milkshakes
menu = [ ['vanilla', 'chocolate', 'almond'],
['vanilla', 'pineapple', 'strawberry'] ]
Now I create a class that takes this array as input
class cafe{
constructor(menu){
this.iceCreams = menu[0]
this.milkshakes = menu[1]
}
}
Now I want to define a property called 'price' for each flavor of milkshake.
this.milkshakes[n].price = < a function that computes price based on value of n >
so that i can access them like this :
cafe.milkshakes[0].price
So how do I incorporate the index 'n' of the array while defining the property
I haven't tried anything bcos I dont know how to even approach this ☹️
You can do it in your constructor.
You can grab the names, and call map function on it and do whatever you want. Please check the following example. There, calculatePrice is a function that takes the index and returns the price based on the index.
class Cafe {
constructor (menu) {
this.iceCreams = menu[0].map((flavor, index) => {
return {
flavor,
price: calculatePrice(index)
}
});
this.milkshakes = menu[1].map((flavor, index) => {
return {
flavor,
price: calculatePrice(index)
}
});
}
This is a minimal answer.
UPDATE:
For a detailed and improved answer: https://codesandbox.io/s/cafe-example-wxp2c4
So, in the milkshakes array you need each item as an object data structure, not a string.
menu = [ ['vanilla', 'chocolate', 'almond'],
[{ flavor: 'vanilla' }, { flavor: 'pineapple' }, { flavor: 'strawberry' }] ]
and then you can loop through and set the price, something like this.
menu.milkshakes.forEach((item, index) => item.price = index))
you can use objects:
menu = [
[
{
name: "vanilla",
price: 200,
},
{
name: "chocolate",
price: 200,
},
{
name: "almond",
price: 200,
},
],
[
{
name: "vanilla",
price: 200,
},
{
name: "pineapple",
price: 200,
},
{
name: "strawberry",
price: 200,
},
],
];
and then:
class cafe{
constructor(menu){
this.iceCreams = menu[0]
this.milkshakes = menu[1]
}
}
now iceCreams and milshakes have the property price and name
example:
iceCreams[n].price
iceCreams[n].name

Returning the ids from the object within the arrays

I have a multidimensional javascript array of objects that I am trying to use to simply collate the Unit id into a new array as shown below.
What is the best solution for returning the id within the inner value so I just get an array of the ids whatever I try seems to not work
[
{
units: [
{
id: 10000282,
name: "Group 1",
},
{
id: 10000340,
name: "Group 2",
},
{
id: 10000341,
name: "Group 3",
},
],
},
{
units: [
{
id: 10000334,
name: "Group 4",
},
],
},
]
Expected output - just return an array with simply the ids
e.g
ids = [ 10000282, 10000340, 10000341, 10000334 ]
Assuming that data is in variable data:
> data.map(o => o.units.map(u => u.id)).flat()
[ 10000282, 10000340, 10000341, 10000334 ]
This assumes you're in an environment where .flat() is a thing.
If that's not the case, the longer way around is
const ids = [];
data.forEach(o => {
o.units.forEach(u => {
ids.push(u.id);
});
});

Convert Object Array To Array With Calculation

I am working with the following object array and attempting to convert it into an array:
const data = [
{
count: 3,
userName: "Paul Crewe",
value: "Activity Type",
},
{
count: 1,
userName: "Nate Scarborough",
value: "Activity Type",
},
{
count: 1,
userName: "Nate Scarborough",
value: "Another Activity Type",
},
{
count: 1,
userName: "Paul Crewe",
value: "Another Activity Type",
},
];
Expected Outcome:
const outcome = [
['userName', 'Paul Crewe', 'Nate Scarborough'],
['Activity Type', 3, 1],
['Another Activity Type', 1, 1]
];
The outcome array takes the data and uses the userName key to create to first array element followed by the format of value, count for each additional array element. For example,
['userName', 'Paul Crewe', 'Nate Scarborough'],
[{value}, {count for Paul Crewe}, {count for Nate Scarborough} ],
I feel that using a reduce is appropriate and have started with:
data.reduce((a, c) => {
a[c.userName] = { value: c.value, count: c.count };
a[c.userName].count += c.count;
return a;
}, {});
But this results in an undesired outcome like:
{
Nate Scarborough: {value: "Another Activity Type", count: 2},
Paul Crewe: {value: "Another Activity Type", count: 2},
}
You could start with the key userName and build new value rows as requires. It works with anrbitrary count of values.
This solution could return an array of sparse arrays. If not wanted, then you need to map the inner array with a default zero.
const
data = [{ count: 3, userName: "Paul Crewe", value: "Activity Type" }, { count: 1, userName: "Nate Scarborough", value: "Activity Type" }, { count: 1, userName: "Nate Scarborough", value: "Another Activity Type" }, { count: 1, userName: "Paul Crewe", value: "Another Activity Type" }],
result = data.reduce((r, o) => {
var vIndex = r.findIndex(([v]) => v === o.value),
index = r[0].indexOf(o[r[0][0]]);
if (vIndex < 0) {
vIndex += r.push([o.value]);
}
if (index < 0) {
index += r[0].push(o[r[0][0]]);
}
r[vIndex][index] = (r[vIndex][index] || 0) + o.count;
return r;
}, [['userName']]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I’m a bit old-school when it comes to working with arrays - I am more comfortable with doing my own loops, than the various “fancy” array methods.
Here’s how I would handle this,
const data = [
{
count: 3,
userName: "Paul Crewe",
value: "Activity Type",
},
{
count: 1,
userName: "Nate Scarborough",
value: "Activity Type",
},
{
count: 1,
userName: "Nate Scarborough",
value: "Another Activity Type",
},
{
count: 1,
userName: "Paul Crewe",
value: "Another Activity Type",
},
];
const temp = {
userName : []
};
data.forEach(function(e) {
// push username only if not in array already
if(temp.userName.indexOf(e.userName) === -1) {
temp.userName.push(e.userName);
}
// create empty array for activity name, if not exists yet
if(!temp[e.value]) {
temp[e.value] = [];
}
temp[e.value].push(e.count)
});
var outcome = [];
// special treatment for userName, to make sure that comes first
temp.userName.unshift('userName');
outcome.push(temp.userName);
for(k in temp) {
if(k != 'userName') {
temp[k].unshift(k); // insert activity name at front of array
outcome.push( temp[k]); // insert array into final result array
}
}
console.log(outcome)
Using the temp helper object makes it easier to access the correct array using the activity name - if I went with the desired structure directly, that would mean looping over the arrays and comparing the first entry all the time to find the right one, whereas with an object a simple property lookup will do.

Why is my objects key, value pair being overridden instead of creating a new key, value pair?

I am trying to create an object of objects within an object with dynamically created key,value pairs, but the nested object keeps overriding the key value pair instead of creating a new key value pair.
ObjectIDWithQuestions = {};
var ArrayOfBlocks1 = [
{
ID: "block1",
block: "block1",
BlockElements: [
{ QuestionID: "1" },
{ QuestionID: "2" }
]
},
{
ID: "block2",
block: "block2",
BlockElements: [
{ QuestionID: "1" },
{ QuestionID: "2" }
]
},
{
ID: "block3",
block: "block3",
BlockElements: [
{ QuestionID: "1" },
{ QuestionID: "2" }
]
}
];
for(i=0;i<ArrayOfBlocks1.length;i++){
for(k=0;k<ArrayOfBlocks1[i].BlockElements.length;k++){
var ArrayOfBlocks2 = ArrayOfBlocks1[i].ID
ObjectIDWithQuestions[ArrayOfBlocks2]={}
ObjectIDWithQuestions[""+ArrayOfBlocks2]["questions"+ k]=ArrayOfBlocks1[i].BlockElements[k].QuestionID
}
}
console.log(ObjectIDWithQuestions);
The expected result of the code is to create an object that is an object of objects that has a two dynamically created key, value pairs instead of one key, value pair that is being overridden.for example, the following code prints:
block1: {questions1: "2"}
block2: {questions1: "2"}
block3: {questions1: "2"}
When it should print
block1: {questions0: "1",questions1:"2"}
block2: {questions0: "1",questions1:"2"}
block3: {questions0: "1",questions1:"2"}
You should initialize
var ArrayOfBlocks2 = ArrayOfBlocks1[i].ID
ObjectIDWithQuestions[ArrayOfBlocks2]={}
outside the inner loop. Otherwise it will create an object every time the inner loop iterates
ObjectIDWithQuestions = {};
var ArrayOfBlocks1 = [
{
ID: "block1",
block: "block1",
BlockElements: [
{ QuestionID: "1" },
{ QuestionID: "2" }
]
},
{
ID: "block2",
block: "block2",
BlockElements: [
{ QuestionID: "1" },
{ QuestionID: "2" }
]
},
{
ID: "block3",
block: "block3",
BlockElements: [
{ QuestionID: "1" },
{ QuestionID: "2" }
]
}
];
for(i=0;i<ArrayOfBlocks1.length;i++){
var ArrayOfBlocks2 = ArrayOfBlocks1[i].ID
ObjectIDWithQuestions[ArrayOfBlocks2]={}
for(k=0;k<ArrayOfBlocks1[i].BlockElements.length;k++){
ObjectIDWithQuestions[""+ArrayOfBlocks2]["questions"+ k]=ArrayOfBlocks1[i].BlockElements[k].QuestionID
}
}
console.log(ObjectIDWithQuestions);
Remove these two lines from inner loop and move it to outside of the inner loop,
ArrayOfBlocks2 = ArrayOfBlocks1[i].ID
ObjectIDWithQuestions[ArrayOfBlocks2] = {}
This should do the trick

Spread values after certain index

I am trying to spread array values into an object after a certain index 3 (column_4).
const array = ['Column_5', 'Column 6', 'Column 7']
const object = {
column_1: '',
column_2: 'Status',
column_3: 'Master',
column_4: 'Locale',
...array
}
At the moment, Column 5/6/7 appear at the start:
{
0: "Column_5",
1: "Column 6",
2: "Column 7",
column_1: "",
column_2: "Status",
column_3: "Master",
column_4: "Locale"
}
But I need them to appear in numerical order. Any ideas? I've tried using Ramda's insert method without any success.
const array = ['column_5', 'column_6', 'column_7']
const object = {
column_1: '',
column_2: 'Status',
column_3: 'Master',
column_4: 'Locale',
...array.reduce((acc, item) => {
acc[item] = item;
return acc;
}, {}),
}
console.log(object);

Categories

Resources