Javascript adding to an object (used as an array) - javascript

I have an object with the below structure and I'm wondering how to add a line to it.
var itemList = {
'1': { type: "car", make: "audi", price: 500, number: 10, description: "a car" },
'2': { type: "bus", make: "renault", price: 50, number: 1, description: "a bus" }
};
line to add:
'3': { type: "truck", make: "volvo", price: 5, number: 20, description: "a truck" },
and I would like to add another line to this array but I have no clue how to even start so any help is welcome!

I assume you need to calculate the next insertion point.
Not sure why you're not using an actual Array, but if you have a fixed offset from 0 and a sequential enumeration from there, you can use Object.keys to get the number of keys for the next index.
const offset = 1;
var itemList = {
'1': { type: "car", make: "audi", price: 500, number: 10, description: "a car" },
'2': { type: "bus", make: "renault", price: 50, number: 1, description: "a bus" }
};
itemList[Object.keys(itemList).length + offset] = { type: "truck", make: "volvo", price: 5, number: 20, description: "a truck" }
console.log(itemList);
But again, this presumes there's some good reason for using this kind of data structure instead of an Array.
And note that the offset can be pre-calculated if it's not known in advance, again assuming the rest of the keys are sequential integers.
var itemList = {
'1': { type: "car", make: "audi", price: 500, number: 10, description: "a car" },
'2': { type: "bus", make: "renault", price: 50, number: 1, description: "a bus" }
};
const offset = Math.min(Object.keys(itemList).length, ...Object.keys(itemList));
itemList[Object.keys(itemList).length + offset] = { type: "truck", make: "volvo", price: 5, number: 20, description: "a truck" }
console.log(itemList);
Or if you don't have a sequential set of numeric keys, but need to add one after the current highest key, you can do this:
var itemList = {
'1': { type: "car", make: "audi", price: 500, number: 10, description: "a car" },
'2': { type: "bus", make: "renault", price: 50, number: 1, description: "a bus" }
};
const next = Math.max(-1, ...Object.keys(itemList)) + 1;
itemList[next] = { type: "truck", make: "volvo", price: 5, number: 20, description: "a truck" }
console.log(itemList);

Surprised none of the other answers have simply suggested switched to an actual array (of objects), because then you could simply push a new object into it.
You can then take advantage of all the useful array methods that are available to change/filter your data.
var itemList = [
{ type: "car", make: "audi", price: 500, number: 10, description: "a car" },
{ type: "bus", make: "renault", price: 50, number: 1, description: "a bus" }
];
const newItem = { type: "kite", make: "adobe", price: 10, number: 12, description: "Woo!" }
itemList.push(newItem);
console.log(itemList);

As rmlan says this is not an array, but an object. You could add your new "item" in the following way:
itemList['3'] = { type: "truck", make: "volvo", price: 5, number: 20, description: "a truck" };

You can just use the index operator like so:
var itemList = {
'1': { type: "car", make: "audi", price: 500, number: 10, description: "a car" },
'2': { type: "bus", make: "renault", price: 50, number: 1, description: "a bus" }
};
itemList[3] = { type: "truck", make: "volvo", price: 5, number: 20, description: "a truck" };
console.log(itemList);

Related

How to merge one object id with same value into new array javascript [duplicate]

This question already has answers here:
Group objects by property in javascript
(8 answers)
Closed 2 months ago.
i have array of object transaction join with product and user table, i want to combine id with same value so it can display two different data in 1 object
Here's my data
let test = [
{
TransactionId: 1, //transaction table
username: "A", //user table
qty: 3, //product table
product_name: "Logitech G733",
price: $100,
description: "Lalalalala",
productId: 10
},
{
TransactionId: 2,
username: "B",
qty: 1,
product_name: "Razer",
price: $200,
description: "Blalalala",
productId: 12
},
{
TransactionId: 1,
username: "A",
qty: 1,
product_name: "Mousepad",
price: $50,
description: "This is mousepad",
productId: 7
},
{
TransactionId: 3,
username: "C",
qty: 2,
product_name: "Headphone",
price: $300,
description: "This is Headphone",
productId: 2
},
]
this is the output i want
let test = [
{
TransactionId: 1,
username: "A",
qty: [3, 1],
product_name: ["Logitech G733", "Mousepad"],
price: [$100, $50]
description: ["Lalalalala", "This is mousepad"],
productId: [10, 7]
},
{
TransactionId: 2,
username: "B",
qty: 1,
product_name: "Razer",
price: $200,
description: "Blalalala",
productId: 12
},
{
TransactionId: 3,
username: "C",
qty: 2,
product_name: "Headphone",
price: $300,
description: "This is Headphone",
productId: 2
},
]
i tried using reduce and Object.assign but the output only shows object with "Mousepad" not make array ["logitech G733","Mousepad"]
there should be many ways to do it, I used a map to combine the transactions and you can do whatever you need for the map after. For example
const test = [
{
TransactionId: 1, //transaction table
username: "A", //user table
qty: 3, //product table
product_name: "Logitech G733",
price: 100,
description: "Lalalalala",
productId: 10
},
{
TransactionId: 2,
username: "B",
qty: 1,
product_name: "Razer",
price: 200,
description: "Blalalala",
productId: 12
},
{
TransactionId: 1,
username: "A",
qty: 1,
product_name: "Mousepad",
price: 50,
description: "This is mousepad",
productId: 7
},
{
TransactionId: 3,
username: "C",
qty: 2,
product_name: "Headphone",
price: 300,
description: "This is Headphone",
productId: 2
},
]
const tMap = new Map();
test.forEach(transation => {
tMap.set(transation.TransactionId, { ...tMap.get(transation.TransactionId), ...transation });
})
If you wan to deep combined you can use some tool like lodash deep merge
tMap.set(transation.TransactionId, _.merge(tMap.get(transation.TransactionId), transation))
Then you have a map based on your tranastion Id, and you can decide what to do next. If you wan the array back you can simple run
console.log(Array.from(tMap.values()));

Generate a total price from the items in state and output it in JSX (React)

I have data in an array of objects:
const data = [
{
id: 1,
category: "tables",
name: "N/A",
price: 0,
},
{
id: 2,
category: "tables",
name: "Table 1",
price: 220,
},
{
id: 3,
category: "tables",
name: "Table 2",
price: 420,
},
{
id: 4,
category: "tables",
name: "Table 3",
price: 515,
},
{
id: 5,
category: "tables",
name: "Table 4",
price: 495,
},
{
id: 6,
category: "tables",
name: "Table 5",
price: 210,
},
{
id: 7,
category: "chairs",
name: "N/A",
price: 0,
},
{
id: 8,
category: "chairs",
name: "Chair 1",
price: 75,
},
{
id: 9,
category: "chairs",
name: "Chair 2",
price: 150,
},
{
id: 10,
category: "desks",
name: "Desk 1",
price: 75,
},
{
id: 11,
category: "desks",
name: "Desk 2",
price: 130,
},
{
id: 12,
category: "desks",
name: "Desk 3",
price: 215,
},
{
id: 13,
category: "desks",
name: "Desk 4",
price: 275,
},
{
id: 14,
category: "lighting",
name: "Lighting 1",
price: 105,
},
{
id: 15,
category: "lighting",
name: "Lighting 2",
price: 150,
},
];
export default data;
I have a reducer which updates the state depending on which items the user selects on the page (via radios, checkboxes and quantity inputs). Here's what the initial state looks like. The nested keys correspond to the ids in data and the values are the quantities, e.g. there are two desks currently selected (with ids 10 and 12, and 1 quantity of each). Lighting has x2 of id 14 and id 15 has its quantity set to zero as this is output on the page as the initial value in a quantity input.
const [reducerState, dispatch] = useReducer(reducer, {
tables: {
1: 1,
},
chairs: {
7: 1,
},
desks: {
10: 1,
12: 1,
},
lighting: {
14: 2,
15: 0,
},
});
What I need to do is calculate a total price based on the ids and quantities in state. In this example it should be £500. How can I generate this and output it on the page in the JSX?
Any help appreciated, thanks.
Here's a working example:
You have to create a reducer function which goes through every selected option, finds that id in the data and then adds the count*price to the sum so far.
https://codesandbox.io/s/keen-sammet-b5m3y9?file=/src/App.js
I do not know what your reducer switch does, but the logic to check and eventually add the price could be:
const totalPriceForType=(data,initState) => data.map(item=>
initState.map(id=>
item.id===id && item.price+=item.price))

Javascript array sorting based on multiple criteria (in one iteration)

I have an array of cars:
enum Condition {
New = 1,
Used = 2
}
type Car = {
make: string;
model: string;
age: number;
condition: Condition;
};
const cars: Car[] = [
{id: "1", make: "BMW", model: "E3", age: 12, condition: Condition.Used},
{id: "2", make: "Audi", model: "A8", age: 4, condition: Condition.Used},
{id: "3", make: "Mercedes", model: "SLK", age: 0, condition: Condition.New},
{id: "4", make: "Ford", model: "CMAX", age: 3, condition: Condition.Used},
{id: "5", make: "Ford", model: "BMAX", age: 0, condition: Condition.New},
{id: "6", make: "Porsche", model: "Panamera", age: 0, condition: Condition.New},
]
And I have a search query:
const searchQuery: Car = {
make: "Ford",
model: "Panamera",
age: 4,
condition: Condition.New
}
I want to have a sorted array based on these rules:
items that exactly matches the make ("Ford") comes first
the rest that exactly matches the model ("Panamera") comes second
the rest that matches the condition of age = 4
the rest that is of condition New,
and at last any item that does not pass any of the tests
First what I did was to filter the array that matched the make and then the model then the age, etc...
And then merged the resulting arrays to a final array (also filtered out duplicates that passed multiple criteria), but that require iterating over the cars as many times as the number of criteria I have.
So I wondered if there is a better way to do it in one pass? Maybe using .sort somehow?
You can create a mapping function to determine your priority and just subtract the normalized value in your sort.
const Condition = { New: 1, Used: 2 };
const cars = [
{id: "1", make: "BMW", model: "E3", age: 12, condition: Condition.Used},
{id: "2", make: "Audi", model: "A8", age: 4, condition: Condition.Used},
{id: "3", make: "Mercedes", model: "SLK", age: 0, condition: Condition.New},
{id: "4", make: "Ford", model: "CMAX", age: 3, condition: Condition.Used},
{id: "5", make: "Ford", model: "BMAX", age: 0, condition: Condition.New},
{id: "6", make: "Porsche", model: "Panamera", age: 0, condition: Condition.New},
];
const searchQuery = {
make: "Ford",
model: "Panamera",
age: 4,
condition: Condition.New
};
const prioritize = (car, query) => {
if (car.make === query.make) return 4;
if (car.model === query.model) return 3;
if (car.age === query.age) return 2;
if (car.condition === query.condition) return 1;
return 0;
};
const sorted = cars.sort((a, b) => {
const prioA = prioritize(a, searchQuery);
const prioB = prioritize(b, searchQuery);
return prioB - prioA;
});
console.log(JSON.stringify(sorted, null, 2));
if you want the sort to work with multiple conditions, e.g. first make and model, you can add a simple recursive check and increment the priority:
const prioritize = (car, query) => {
const { make, model, age, condition } = query;
if (car.make === make) return 4 + prioritize(car, { model, age, condition });
if (car.model === model) return 3 + prioritize(car, { age, condition });
if (car.age === age) return 2 + prioritize(car, { condition });
if (car.condition === condition) return 1;
return 0;
};
in here, you just check the other query options next in line.
I suggest to use a different approach by checking the wanted first sorted condition first and then by the lower conditions.
This approach sorts ford with new condition first, instead of only ford first.
const
Condition = { New: 1, Used: 2 },
cars = [{ id: "1", make: "BMW", model: "E3", age: 12, condition: Condition.Used }, { id: "2", make: "Audi", model: "A8", age: 4, condition: Condition.Used }, { id: "3", make: "Mercedes", model: "SLK", age: 0, condition: Condition.New }, { id: "4", make: "Ford", model: "CMAX", age: 3, condition: Condition.Used }, { id: "5", make: "Ford", model: "BMAX", age: 0, condition: Condition.New }, { id: "6", make: "Porsche", model: "Panamera", age: 0, condition: Condition.New }],
searchQuery = { make: "Ford", model: "Panamera", age: 4, condition: Condition.New };
cars.sort((a, b) =>
(b.make === searchQuery.make) - (a.make === searchQuery.make) ||
(b.model === searchQuery.model) - (a.model === searchQuery.model) ||
(b.age === searchQuery.age) - (a.age === searchQuery.age) ||
(b.condition === searchQuery.condition) - (a.condition === searchQuery.condition)
);
console.log(cars); // 5 4 6 2 3 1 instead of 4 5 6 1 2 3
.as-console-wrapper { max-height: 100% !important; top: 0; }
It can be considered as priority sort. Give different priorities(points) and calculate total points.
JS Version
var Condition;
(function (Condition) {
Condition[(Condition["New"] = 1)] = "New";
Condition[(Condition["Used"] = 2)] = "Used";
})(Condition || (Condition = {}));
const priority = {
make: 5,
model: 4,
age: 3,
condition: 2,
};
const calculatePoint = (obj, params) =>
Object.entries(obj).reduce((p, [key, value]) => {
if (value === params[key]) p += priority[key];
return p;
}, 0);
const sortData = (data, params) =>
data.sort((x, y) => calculatePoint(y, params) - calculatePoint(x, params));
const cars = [{"id":"1","make":"BMW","model":"E3","age":12,"condition":2},{"id":"2","make":"Audi","model":"A8","age":4,"condition":2},{"id":"3","make":"Mercedes","model":"SLK","age":0,"condition":1},{"id":"4","make":"Ford","model":"CMAX","age":3,"condition":2},{"id":"5","make":"Ford","model":"BMAX","age":0,"condition":1},{"id":"6","make":"Porsche","model":"Panamera","age":0,"condition":1}]
const searchQuery = {
make: "Ford",
model: "Panamera",
age: 4,
condition: Condition.New,
};
console.log(sortData(cars, searchQuery));
TS version
enum Condition {
New = 1,
Used = 2,
}
type Car = {
id?: string;
make: string;
model: string;
age: number;
condition: Condition;
};
const cars: Car[] = [{"id":"1","make":"BMW","model":"E3","age":12,"condition":2},{"id":"2","make":"Audi","model":"A8","age":4,"condition":2},{"id":"3","make":"Mercedes","model":"SLK","age":0,"condition":1},{"id":"4","make":"Ford","model":"CMAX","age":3,"condition":2},{"id":"5","make":"Ford","model":"BMAX","age":0,"condition":1},{"id":"6","make":"Porsche","model":"Panamera","age":0,"condition":1}]
;
const searchQuery: Car = {
make: "Ford",
model: "Panamera",
age: 4,
condition: Condition.New,
};
const priority = {
make: 5,
model: 4,
age: 3,
condition: 2,
};
const calculatePoint = (obj: Car, params: Car) =>
Object.entries(obj).reduce((p: number, [key, value]) => {
if (value === params[key]) p += priority[key];
return p;
}, 0);
const sortData = (data: Car[], params: Car) =>
data.sort(
(x: Car, y: Car) => calculatePoint(y, params) - calculatePoint(x, params)
);
console.log(sortData(cars, searchQuery));

remove object property inside of object

I have an object of object
cart {
KDR010011: {
barcode: "0"
brand: "Kapal Api"
category: "KEBUTUHAN DAPUR"
cost_price: "107569.66490299824"
cost_price_per_piece: 896.413874191652
name: "Kapal Api 25g sp mix"
product_id: "KDR010011"
qty: 1
qty_per_box: 120
selling_price: 116000
selling_price_per_piece: 962.5
},
KDR010125: {
barcode: ""
brand: "Kapal Api"
category: "KEBUTUHAN DAPUR"
cost_price: "110317.63859070961"
cost_price_per_piece: 835.7396862932546
name: "ABC Susu 31g"
product_id: "KDR010125"
qty: 5
qty_per_box: 132
selling_price: 113000
selling_price_per_piece: 863.6363636363636
}
}
and I want to remove the property, the result what I want:
cart {
KDR010011: {
qty: 1
selling_price: 116000
},
KDR010125: {
qty: 5
selling_price: 113000
}
}
I am using underscore js library, the result is this:
What should I do?
You can achieve this easily by looping over the keys of the object and assigning the value for each key back to the original object. If you don't want to modify the original object just assign the keys to a new one.
Personally I'd change my data structure so that the cart was an array of objects and each object had the KDR010011 key as a property instead.
const obj = {
KDR010011: {
barcode: "0",
brand: "Kapal Api",
category: "KEBUTUHAN DAPUR",
cost_price: "107569.66490299824",
cost_price_per_piece: 896.413874191652,
name: "Kapal Api 25g sp mix",
product_id: "KDR010011",
qty: 1,
qty_per_box: 120,
selling_price: 116000,
selling_price_per_piece: 962.5,
},
KDR010125: {
barcode: "",
brand: "Kapal Api",
category: "KEBUTUHAN DAPUR",
cost_price: "110317.63859070961",
cost_price_per_piece: 835.7396862932546,
name: "ABC Susu 31g",
product_id: "KDR010125",
qty: 5,
qty_per_box: 132,
selling_price: 113000,
selling_price_per_piece: 863.6363636363636,
}
}
Object.keys(obj).forEach(key => obj[key] = {
qty: obj[key].qty,
selling_price: obj[key].selling_price,
})
console.log(obj)
You can try this:
const newCart = {...cart}
Object.keys(newCart).forEach(key => {
newCart[key] = {
qty: newCart[key].qti,
selling_price: newCart[key].sailing_price
}
}
You need commas in your object
I have a feeling I could use destructuring better than here
const cart = {
KDR010011: {
barcode: "0",
brand: "Kapal Api",
category: "KEBUTUHAN DAPUR",
cost_price: "107569.66490299824",
cost_price_per_piece: 896.413874191652,
name: "Kapal Api 25g sp mix",
product_id: "KDR010011",
qty: 1,
qty_per_box: 120,
selling_price: 116000,
selling_price_per_piece: 962.5
},
KDR010125: {
barcode: "",
brand: "Kapal Api",
category: "KEBUTUHAN DAPUR",
cost_price: "110317.63859070961",
cost_price_per_piece: 835.7396862932546,
name: "ABC Susu 31g",
product_id: "KDR010125",
qty: 5,
qty_per_box: 132,
selling_price: 113000,
selling_price_per_piece: 863.6363636363636
}
}
let newCart = {}
Object.keys(cart).forEach(key => newCart[key] = { qty: cart[key].qty, selling_price : cart[key].selling_price })
console.log(newCart)

JavaScript grabbing certain values of multi-dimensional arrays

I'm trying to make a simple 'Choose Your Adventure!' game, and I seem to have run into a problem. I don't know how to target certain values of this multi-dimensional array I made.
I made a 'dealer/trader' and have his items on sale like this.
var dealer = [
[
{type: "weapon", cost: 250, name: "Claymore"},
{type: "weapon", cost: 75, name: "Dagger"},
{type: "weapon", cost: 350, name: "Magic Staff"},
{type: "weapon", cost: 150, name: "Sword"},
{type: "weapon", cost: 125, name: "Bow"},
{type: "weapon", cost: 125, name: "Crossbow"},
{type: "weapon", cost: 5, name: "Arrow"},
{type: "weapon", cost: 15, name: "Bolt"}
],
[
{type: "clothing", slot: "head", name: "Helmet"},
{type: "clothing", slot: "head", name: "Hood"},
{type: "clothing", slot: "chest", name: "Chestplate"},
{type: "clothing", slot: "chest", name: "Tunic"},
{type: "clothing", slot: "chest", name: "Robe"},
{type: "clothing", slot: "leggings", name: "Legplates"},
{type: "clothing", slot: "leggings", name: "Leggings"},
{type: "clothing", slot: "leggings", slot: "Undergarments"},
{type: "clothing", slot: "feet", name: "Boots"},
{type: "clothing", slot: "feet", name: "Armored Boots"}
]
]
And I have a function that operates the dealer, such as buying an item, I don't know how to target certain values/arrays. This is what I THINK will work.
function merchant() = {
var armor = function(slot, name, material) {
if(dealer[2].slot === "feet" && dealer[2].name = "Boots"}
money -= 10;
}
}
}
That should target the second array of the clothing and look for the slot feet and name of boots, right?
I would make the merchants array contain merchant objects. This allows you to give more information about a merchant, including items. I have two find methods. The first takes static arguments, the second allows for key-value parameters.
Note: I added a cost field to your boots, as this was somehow related to your example.
var merchants = [{
name : 'Weapons Merchant',
items : [
{type: "weapon", cost: 250, name: "Claymore"},
{type: "weapon", cost: 75, name: "Dagger"},
{type: "weapon", cost: 350, name: "Magic Staff"},
{type: "weapon", cost: 150, name: "Sword"},
{type: "weapon", cost: 125, name: "Bow"},
{type: "weapon", cost: 125, name: "Crossbow"},
{type: "weapon", cost: 5, name: "Arrow"},
{type: "weapon", cost: 15, name: "Bolt"}
]
}, {
name : 'Armor Merchant',
items : [
{type: "clothing", slot: "head", name: "Helmet"},
{type: "clothing", slot: "head", name: "Hood"},
{type: "clothing", slot: "chest", name: "Chestplate"},
{type: "clothing", slot: "chest", name: "Tunic"},
{type: "clothing", slot: "chest", name: "Robe"},
{type: "clothing", slot: "leggings", name: "Legplates"},
{type: "clothing", slot: "leggings", name: "Leggings"},
{type: "clothing", slot: "leggings", name: "Undergarments"},
{type: "clothing", slot: "feet", name: "Boots", cost : 10},
{type: "clothing", slot: "feet", name: "Armored Boots"}
]
}];
function main() {
// Static approach
var armorMerchant = findMerchant(merchants, 'Armor Merchant');
var boots = findItem(armorMerchant, 'clothing', 'Boots');
print('Boots: $' + boots.cost);
// Dynamic approach
var weaponsMerchant = findMerchant(merchants, 'Weapons Merchant');
var dagger = findWithParams(weaponsMerchant.items, {type:"weapon",name:"Dagger"});
print('Dagger: $' + dagger.cost);
}
function findMerchant(merchants, name) {
return find(merchants, function(merchant) {
return merchant.name === name;
});
}
function findItem(merchant, type, name) {
return find(merchant.items, function(item) {
return item.type === type && item.name === name;
});
}
function findWithParams(arr, parameters) {
return find(arr, function(item) {
for (var parameter in parameters) {
if (item[parameter] !== parameters[parameter]) {
return false;
}
return true;
}
});
}
function find(arr, predicateFn) {
var found = null;
arr.forEach(function(item, index, items) {
if (predicateFn.apply(undefined, arguments)) {
found = item;
return true;
}
return false;
});
return found;
}
function print(text) {
document.getElementById('out').innerHTML += text + '<br />';
}
main();
<div id="out"></div>

Categories