I'm new to JavaScript and working on a personal program which creates car objects and stores them in an array, I am having issues with returning all array elements as only the first array element is returned.
const carFactory = {
_cars:[
{
make: 'default',
model: 'default',
year: 0,
}
],
get cars(){
if(this._cars.length > 0 ){
for(let i = 0; i < this._cars.length; i++){
return `Car Make: ${this._cars[i].make} - Car Model: ${this._cars[i].model} Manufacture Year: ${this._cars[i].year}`;
}
}else{
return `Please add car details`;
}
},
addCar(carMake, carModel, carYear){
this._cars.push({
carMake,
carModel,
carYear
})
}
}
carFactory.addCar('Toyota', 'Corolla', 2003);
console.log(carFactory.cars);
The issue with your code is that the return statement inside the for loop only returns the first car object in the _cars array and terminates the loop. To return all cars, you can concatenate the car objects into a string and return it after the loop:
const carFactory = {
_cars:[
{
make: 'default',
model: 'default',
year: 0,
}
],
get cars(){
if(this._cars.length > 0 ){
let allCars = '';
for(let i = 0; i < this._cars.length; i++){
allCars += `Car Make: ${this._cars[i].make} - Car Model: ${this._cars[i].model} Manufacture Year: ${this._cars[i].year}\n`;
}
return allCars;
}else{
return `Please add car details`;
}
},
addCar(carMake, carModel, carYear){
this._cars.push({
make: carMake,
model: carModel,
year: carYear
})
}
}
carFactory.addCar('Toyota', 'Corolla', 2003);
console.log(carFactory.cars);
Output:
Car Make: default - Car Model: default Manufacture Year: 0
Car Make: Toyota - Car Model: Corolla Manufacture Year: 2003
You have a return in your for, which will exit the loop at the first iteration:
for(let i = 0; i < this._cars.length; i++){
return `Car Make: ${this._cars[i].make} - Car Model: ${this._cars[i].model} Manufacture Year: ${this._cars[i].year}`;
}
if you want an array in return then return an array. and addCar method need to have right name.
const carFactory = {
_cars: [
{
make: 'default',
model: 'default',
year: 0,
}
],
get cars() {
if (this._cars.length > 0) {
let allCars = [];
for (let i = 0; i < this._cars.length; i++) {
let c = `Car Make: ${this._cars[i].make} - Car Model: ${this._cars[i].model} Manufacture Year: ${this._cars[i].year}`;
allCars.push(c)
}
return allCars
} else {
return `Please add car details`;
}
},
addCar(make, model, year) {
this._cars.push({
make,
model,
year
})
}
}
carFactory.addCar('Toyota', 'Corolla', 2003);
console.log(carFactory.cars);
Related
I have two arrays of objects. I need to check if the element called quantity is larger in one of the two arrays.
Example:
Array detail:
[
{
provider: { uid: '6271a32082193f4b88e292f0', name: 'Genérico' },
_id: '628ff19af062bde6a9fd7a3b',
name: 'MALBORO ARTESANAL "20"',
quantity: 6,
subtotal: 3156,
total: 0,
quantityOnBd: 6
},
{
provider: { uid: '6271a32082193f4b88e292f0', name: 'Genérico' },
_id: '628fef9bf062bde6a9fd7986',
name: 'MALBORO ROJO "20"',
quantity: 7,
subtotal: 4368,
total: 0,
quantityOnBd: 7
}
]
Array sale.detail:
[
{
provider: { uid: '6271a32082193f4b88e292f0', name: 'Genérico' },
_id: '628fef9bf062bde6a9fd7986',
name: 'MALBORO ROJO "20"',
quantity: 7,
subtotal: 4368,
total: 0
},
{
provider: { uid: '6271a32082193f4b88e292f0', name: 'Genérico' },
_id: '628ff19af062bde6a9fd7a3b',
name: 'MALBORO ARTESANAL "20"',
quantity: 6,
subtotal: 3156,
total: 0
}
]
I already have a code in which I use two FOR to know if at a certain moment the quantity is greater in one of the two, it works but I would like to know if there is a better way to do it that is more efficient.
for (let i = 0; i < detail.length; i++) {
for (let j = 0; j < sale.detail.length; j++) {
if (detail[i]['_id'] === sale.detail[j]['_id']) {
if (detail[i]['quantity'] > sale.detail[j]['quantity']) {
return res.status(400).json({msg:'No puedes regresar mas de la cantidad original'});
}
}
}
}
Something like this:
const map = new Map();
for (const item of detail) {
let tuple = map[item._id]
if (!tuple) {
tuple = {};
map.set( item._id, tuple ) ;
}
tuple.item = item;
}
for (const sale of sale.detail) {
let tuple = map[sale._id]
if (!tuple) {
tuple = {};
map.set( sale._id, tuple );
}
tuple.sale = sale;
}
for (const [id,{item,sale}] of map.entries() {
if (!item && sale) {
console.log(`id:${id} : sale without item`);
} else if ( item && !sale ) {
console.log(`id:${id} : item without sale`);
} else if (item && sale) {
switch ( Math.sign( item.quantity - sale.quantity ) ) {
case 0 : console.log(`id:${id} : sale.quantity === item.quantity`); break;
case 1 : console.log(`id:${id} : item.quantity > sale.quantity` ); break;
case -1 : console.log(`id:${id} : item.quantity < sale.quantity` ); break;
default:
throw new Error('unreachable code reached')
}
} else {
throw new Error("unreachable code reached: no sale and no item");
}
}
you can save any object in Object use _id in object key, such as
{
"628ff19af062bde6a9fd7a3b":{
provider: { uid: '6271a32082193f4b88e292f0', name: 'Genérico' },
_id: '628ff19af062bde6a9fd7a3b',
name: 'MALBORO ARTESANAL "20"',
quantity: 6,
subtotal: 3156,
total: 0,
quantityOnBd: 6
}
}
full code
const map = {};
detail.forEach(e=>{
map[e._id] = e;
});
const hasLarger = sale.detail.some(e=>{
const { _id , quantity:saleQuantity } = e;
const detailQuantity = map[_id].quantity;
if(detailQuantity>saleQuantity){
return true;
}
return false;
});
if(hasLarger){
return res.status(400).json({msg:'No puedes regresar mas de la cantidad original'});
}
I have an array of vehicles that are available to buy on a company website. Within the van array there is a nested array that contains the model and the vehicle value.
{vanNumber: "7654628", vanDescription: "VW Campervan", value: {make: "VW", amount: 11660}}
{vanNumber: "9873093", vanDescription: "Renault Campervan", value: {make: "Renault", amount: 3429}}
{vanNumber: "1739566", vanDescription: "Nissan Campervan", value: {make: "Nissan", amount: 5600}}
{vanNumber: "3949219", vanDescription: "VW", value: {make: "VW", amount: 1960}}
I'm trying to return an array for each car brand and the total value of each individual brand. I already have the addition part working but I'm trying to loop through the array and return a new array for each car manufacturer.
So in this example, I would like to return a VW array that contains the two VW vehicles based on the value.make value and two other arrays, one for the Nissan and one for the Renault.
I was previously returning the array like this (see below)
// returns an array of VW vehicles when make = VW
if (vanMake != undefined) {
let result = vanMake.filter((x) => {
return x.value.make === 'VW';
});
return result
}
But if I added 3000 cars to the array, I'd like to return a new array to the view for each manufacturer and the total value of each car under that make without having to do an if else for every car brand.
export function toTotalVanValue(state: fromVans.State): any {
let vanMake = state.vans.vanDetails.vehicle;
//prints out the array of objects
console.log('vanMake', vanMake);
if (vanMake != undefined) {
let result = vanMake.filter((x) => {
let make = x.value.make;
if (make) {
console.log ('make', make);
return make
}
return x.value.make;
});
result.forEach(function(element) {
vanMake.filter((x) => {
console.log('x.value.make', x.value.make);
return x.value.make;
});
//prints out each element individually
console.log('element element', element);
});
//prints out the array of objects
console.log('result', result);
return result
}
}
I'm not sure if this is the EXACT structure that you're looking for but you can use collection.reduce to consolicate your colllection into the value that you want.
const vehicles = [
{
vanNumber: "7654628",
vanDescription: "VW Campervan",
value: {
make: "VW",
amount: 11660
}
}, {
vanNumber: "9873093",
vanDescription: "Renault Campervan",
value: {
make: "Renault",
amount: 3429
}
}, {
vanNumber: "1739566",
vanDescription: "Nissan Campervan",
value: {
make: "Nissan",
amount: 5600
}
}, {
vanNumber: "3949219",
vanDescription: "VW",
value: {
make: "VW",
amount: 1960
}
}];
const results = vehicles.reduce((accumalator, current) => {
const { make } = current.value;
console.log(make);
if (accumalator[make]) {
accumalator[make].push(current);
return accumalator;
}
accumalator[make] = [current];
return accumalator;
}, {});
console.log(Object.keys(results));
console.log(results);
One possible approach that solves this kind of problem is, as so often, based on Array.reduce ...
var vehicleList = [
{vanNumber: "7654628", vanDescription: "VW Campervan", value: {make: "VW", amount: 11660}},
{vanNumber: "9873093", vanDescription: "Renault Campervan", value: {make: "Renault", amount: 3429}},
{vanNumber: "1739566", vanDescription: "Nissan Campervan", value: {make: "Nissan", amount: 5600}},
{vanNumber: "3949219", vanDescription: "VW", value: {make: "VW", amount: 1960}}
];
function collectAndGroupVehicleItemByBrand(collector, vehicleItem) {
var
list = collector.list,
index = collector.index,
make = vehicleItem.value.make,
group;
if (make in index) {
group = index[make];
} else {
group = index[make] = { make: make, count: 0, list: [] };
list.push(group);
}
group.count = group.list.push(vehicleItem);
return collector;
}
var dictionary = vehicleList.reduce(collectAndGroupVehicleItemByBrand, {
list : [],
index : {}
});
console.log('groupedVehicleList : ', dictionary.list);
console.log('groupedVehicleIndex : ', dictionary.index);
.as-console-wrapper { max-height: 100%!important; top: 0; }
I have to merge 2 array of object from rest api calls.
They are like: [{date: date, name: name}, ...]
Let's call them A array and B array.
If in the A arrays and B arrays have the same date, the final array-s object should like look this: [{date: date, nameA: nameA, nameB: nameB}]
If they dont, just insert insert and object like this: [{date: dateA, nameA: nameA}]
For example:
arrayA = [
{
date: 2017-01-01,
name: 'New Year Eve'}
},
{
date: 2017-02-02,
name: 'feb2'
}
]
arrayB = [
{
date: 2017-01-01,
name: 'New Year Eve'}
},
{
date: 2017-03-03,
name: 'march3'
}
]
The final array should look like this:
finalArray = [{
date: 2017 - 01 - 01,
nameA: 'New Year Eve',
nameB: 'New Year Eve'
},
{
date: 2017 - 02 - 02,
nameA: 'feb2'
},
{
date: 2017 - 03 - 03,
nameB: 'march3'
}
]
And the objects with shared date can be in different position in the array, so i can't check simple like
arrayA[0].date === arrayB[0].date
You could use a hash table for the reference to the objects with the same date.
var arrayA = [{ date: '2017-01-01', name: 'New Year Eve' }, { date: '2017-02-02', name: 'feb2' }],
arrayB = [{ date: '2017-01-01', name: 'New Year Eve' }, { date: '2017-03-03', name: 'march3' }],
merged = function merge(arrays, names) {
var hash = Object.create(null),
result = [];
arrays.forEach(function (a, i) {
a.forEach(function (b) {
if (!hash[b.date]) {
hash[b.date] = { date: b.date };
result.push(hash[b.date]);
}
hash[b.date][names[i]] = b.name;
});
});
return result;
}([arrayA, arrayB], ['nameA', 'nameB']);
console.log(merged);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var finalArr = [];
for (var i = 0; i < arrayA.length; i++) {
for (var j = 0; j < arrayB.length; j++) {
if (arrayA[i].date == arrayB[j].date) {
//add to the final array if not exist that date
}
}
}
There is something called Array.prototype.concat() and it is used to merge 2 arrays or more, in your example it is like this:
finalArray = arrayA.concat(arrayB)
And then you have to loop over the finalArray, delete any repeated date after taking its attributes and merge to the same date like that:
for (var i = 0; i < finalArray.length; i++) {
if (finalArray[i]["date"] === finalArray[i+1]["date"] ) {
finalArray[i]["nameA"] = finalArray[i]["name"];
finalArray[i]["nameB"] = finalArray[i+1]["name"];
//delete the one that is repeated
delete finalArray[i+1][key]
}
}
Hope that works
You can use array from and subtract the length
var arrayA = [{date: '2017-01-01', name: 'New Year Eve'},{date: '2017-02-02', name: 'feb2'}];var arrayB = [{date: '2017-01-01', name: 'New Year Eve'},{date: '2017-03-03',name: 'march3'}];
var arr= Array.from(new Array(arrayA.length+arrayB.length),(x,y)=> arrayB[y]||arrayA[y-arrayA.length] );
console.log(arr);
My code is as follows :
let filters = [
{name: "MAKE", values:
[
{
Volkswagen: {active: true, make: "Volkswagen"},
Skoda: {active: true, make: "Skoda"}
}
]
}
]
function getFilterValues(){
return filters.filter(f => {
if(f.name == "MAKE"){
return f.values.filter(i => {
Object.keys(i).map(key => {
return key;
});
});
}
});
}
var div = document.getElementById('output');
div.innerHTML = getFilterValues();
I want to loop through filters to get the object keys.
Thus the result that I want is, in this case Volkswagen, Skoda. But my function getFilterValues doesn't return what I want.
Here is jsfiddle.
Any advice?
The main problem is with the filter function. You want map since with filter you return true/false whether the element should be included in the resulting code. Check out this diff: https://www.diffchecker.com/CX6hOoxo
This works: https://jsfiddle.net/o93Lm0rc/101/
let filters = [
{name: "MAKE", values:
[
{
Volkswagen: {active: true, make: "Volkswagen"},
Skoda: {active: true, make: "Skoda"}
}
]
}
]
function getFilterValues(){
return filters.map(f => {
if(f.name == "MAKE"){
return f.values.map(i => {
return Object.keys(i).map(key => {
return key;
});
});
}
});
}
var div = document.getElementById('output');
div.innerHTML = getFilterValues();
You can use Object.keys() to get the list of keys.
var filters = [{
name: "MAKE",
values: [{
Volkswagen: {
active: true,
make: "Volkswagen"
},
Skoda: {
active: true,
make: "Skoda"
}
}]
}];
for (i = 0; i < filters.length; i++) {
if (typeof filters[i].values == "object") {
console.log(Object.keys(filters[i].values[0]));
}
}
I have an array of invoices and I want to compile an ordered list of monthlyIncome based on a value invoiceMonth (e.g. "February 2014"). The monthlyIncome array has to store the month name and the income for that month, i.e.
monthlyIncome = [
{ name: 'January 2014', income: 1000},
{ name: 'February 2014', income: 1500 }
...
];
Basically what I need is a "deeper" sort of indexOf(val), that would check if val is in a specified property of any object of monthlyIncome, and then return that index. In this example I use deepIndexOf(value, property).
for (var i=0; i<invoices.length; i++) {
var index = monthlyIncome.deepIndexOf(invoices[i].invoiceMonth, 'name');
if (index > -1) {
// month already exists in list, so add the total
monthlyIncome[index].income += invoice.total;
} else {
// month doesn't exist, so add it
monthlyIncome.push({
name: invoices[i].invoiceMonth,
income: invoices[i].total
});
}
}
The only problem is that I don't know exactly how I would write deepIndexOf. Also, I suspect there is a better way to do this in JavaScript than the way I've outlined.
Your deepIndexOf function can be like:
function deepIndexOf(array, key, value) {
var obj;
for (var idx = 0; idx < array.length; idx++) {
var obj = array[idx];
if (obj[key] === value) {
return idx;
}
}
return -1;
}
var monthlyIncome = [{
name: 'January 2014',
income: 1000
}, {
name: 'February 2014',
income: 1500
}];
console.log(deepIndexOf(monthlyIncome, 'name', 'January 2014'));
console.log(deepIndexOf(monthlyIncome, 'name', 'February 2014'));
console.log(deepIndexOf(monthlyIncome, 'name', 'None 2014'));
Or, the entire code to compile can be like:
function compile(incomeList, invoice) {
var found = false;
for (var i = 0; i < incomeList.length && !found; i++) {
if (incomeList[i].name === invoice.invoiceMonth) {
incomeList[i].income += invoice.total;
found = true;
}
}
if (!found) {
incomeList.push({
name: invoice.invoiceMonth,
income: invoice.total
});
}
}
compile(monthlyIncome, {
invoiceMonth: 'January 2014',
total: 1000
});
compile(monthlyIncome, {
invoiceMonth: 'March 2014',
total: 1000
});
You can do the following to return the first index that matches a property value in your array:
Live Demo
function indexByPropertyVal(values, propName, propVal){
var i = 0,
count = values.length;
for(; i < count; i++){
if(values[i][propName] === propVal){
return i;
}
}
return -1;
}
monthlyIncome = [
{ name: 'January 2014', income: 1000},
{ name: 'February 2014', income: 1500 },
{ name: 'March 2014', income: 1500 } ,
{ name: 'April 2014', income: 1500 } ,
{ name: 'May 2014', income: 1500 }
];
alert(indexByPropertyVal(monthlyIncome, 'name', 'April 2014'));
alert(indexByPropertyVal(monthlyIncome, 'name', 'June 2014'));
Then just update this line in your code from:
var index = monthlyIncome.deepIndexOf(invoices[i].invoiceMonth, 'name');
to
var index = indexByPropertyVal(monthlyIncome, 'name', invoices[i].invoiceMonth);
You can also augment the prototype of the Array to include the function:
Live Demo
Array.prototype.indexByPropertyVal = function(propName, propVal){
var i = 0,
count = this.length;
for(; i < count; i++){
if(this[i][propName] === propVal){
return i;
}
}
return -1;
};
Then just update this line in your code from:
var index = monthlyIncome.deepIndexOf(invoices[i].invoiceMonth, 'name');
to
var index = monthlyIncome.indexByPropertyVal('name', invoices[i].invoiceMonth);