Javascript sort array by date and alphabetical order - javascript

I want it to be sorted by date and alphabet in one sort how can i do that ?
I think alphabetical order works good but date not works properly. Thanks for answers.
Data structure :
[{
productId: 21,
title: "Huawei P40 Lite ",
brand: "Huawei",
price: 120,
discountPercentage: 10,
color: "Black",
createdDate: "2021-01-15T01:00:00+03:00",
},
{
productId: 22,
title: "Huawei P40 Lite",
brand: "Huawei",
price: 1026,
discountPercentage: 0,
color: "Green",
createdDate: "2021-01-16T01:00:00+03:00",
},
{
productId: 23,
title: "Apple iPhone 11",
brand: "Apple",
price: 1220,
discountPercentage: 11,
color: "White",
createdDate: "2021-01-17T01:00:00+03:00",
},
{
productId: 24,
title: "Apple iPhone 12",
brand: "Apple",
price: 1420,
discountPercentage: 11,
color: "White",
createdDate: "2021-01-18T01:00:00+03:00",
}],
Here my work :
jsfiddle.net/pazyqb01/
And tried different solutions for sort date somehow i couldn't make it work.
Sorted Array shoul be like above :
{
productId: 24,
title: "Apple iPhone 12",
brand: "Apple",
price: 1420,
discountPercentage: 11,
color: "White",
createdDate: "2021-01-18T01:00:00+03:00",
},
{
productId: 23,
title: "Apple iPhone 11",
brand: "Apple",
price: 1220,
discountPercentage: 11,
color: "White",
createdDate: "2021-01-17T01:00:00+03:00",
},
{
productId: 22,
title: "Huawei P40 Lite",
brand: "Huawei",
price: 1026,
discountPercentage: 0,
color: "Green",
createdDate: "2021-01-16T01:00:00+03:00",
},
{
productId: 21,
title: "Huawei P40 Lite ",
brand: "Huawei",
price: 120,
discountPercentage: 10,
color: "Black",
createdDate: "2021-01-15T01:00:00+03:00",
},

this way:
simply follow the list of your sorting criteria
const data =
[ { productId: 21, title: 'Huawei P40 Lite ', brand: 'Huawei', price: 120, discountPercentage: 10, color: 'Black', createdDate: '2021-01-15T01:00:00+03:00' }
, { productId: 22, title: 'Huawei P40 Lite', brand: 'Huawei', price: 1026, discountPercentage: 0, color: 'Green', createdDate: '2021-01-16T01:00:00+03:00' }
, { productId: 23, title: 'Apple iPhone 11', brand: 'Apple', price: 1220, discountPercentage: 11, color: 'White', createdDate: '2021-01-17T01:00:00+03:00' }
, { productId: 24, title: 'Apple iPhone 12', brand: 'Apple', price: 1420, discountPercentage: 11, color: 'White', createdDate: '2021-01-18T01:00:00+03:00' }
]
const fSort = (a,b) =>
{
let Dx = new Date(b.createdDate) - new Date(a.createdDate) // 1st criteria
if (Dx===0) Dx = a.title.trim().localeCompare(b.title.trim()) // 2nd
// if (Dx===0) Dx = ... // 3rd
// if (Dx===0) Dx = ... // 4th....
return Dx
}
console.log( data.sort(fSort))

Related

JS push object with dynamic keys and values to an array

I have an array of objects with dynamic keys and values (so not all objects have category_id, size and so on) but I simplified it to this:
let products_row = [
{
id: 1,
category_id: 11,
options: {
'modelName1': {
size: '2 feet',
colour: 'red',
is_new: true
},
'modelName2': {
size: '4 feet',
colour: 'black',
is_new: true
},
}
},
{
id: 2,
category_id: 21,
options: {
'modelName11': {
size: '2 feet',
colour: 'white',
is_new: false
},
'modelName12': {
size: '4 feet',
colour: 'white',
is_new: false
},
}
},
{
id: 3,
category_id: 31,
options: {
'modelName21': {
size: '8 feet',
colour: 'white',
is_new: false
},
'modelName22': {
size: '4 feet',
colour: 'black',
is_new: true
},
}
},
{
id: 4,
category_id: 41,
options: {
'modelName31': {
size: '8 feet',
colour: 'red',
is_new: true
},
'modelName32': {
size: '8 feet',
colour: 'red',
is_new: true
},
}
}
]
the result data structure needs to be like this:
let resultArray = [
{
id: 1,
category_id: 11,
model: 'modelName1',
size: '2 feet',
colour: 'red',
is_new: true
},
{
id: 1,
category_id: 11,
model: 'modelName2',
size: '4 feet',
colour: 'black',
is_new: true
},
{
id: 2,
category_id: 21,
model: 'modelName11',
size: '2 feet',
colour: 'white',
is_new: false
},
{
id: 2,
category_id: 21,
model: 'modelName12',
size: '4 feet',
colour: 'white',
is_new: false
},
{
id: 3,
category_id: 31,
model: 'modelName21',
size: '8 feet',
colour: 'white',
is_new: false
},
{
id: 3,
category_id: 31,
model: 'modelName22',
size: '4 feet',
colour: 'black',
is_new: true
},
{
id: 4,
category_id: 41,
model: 'modelName31',
size: '8 feet',
colour: 'red',
is_new: true
},
{
id: 4,
category_id: 41,
model: 'modelName32',
size: '8 feet',
colour: 'red',
is_new: true
},
]
This is what I have tried:
let productsData = [];
products_row
.map((product, p) => Object.entries(product.options || {})
.filter((model, i) => {
return productsData.push(
{
model: model[0],
[Object.keys(product).filter(el => delete product.options)[i]]: Object.values(product)[i],
[Object.keys(model[1] || [])[i]]: Object.values(model[1] || [])[i],
}
)
})
)
console.log(productsData)
But it returns not all data, which is expected because I can't figure out how to keep previous key-values:
[
{
model: 'modelName1',
id: 1,
size: '2 feet',
},
{
model: 'modelName2',
category_id: 11,
colour: 'black',
},
{
model: 'modelName11',
id: 2,
size: '2 feet',
},
{
model: 'modelName12',
category_id: 21,
colour: 'white',
},
{
model: 'modelName21',
id: 3,
size: '8 feet',
},
{
model: 'modelName22',
category_id: 31,
colour: 'black',
},
{
model: 'modelName31',
id: 4,
size: '8 feet',
},
{
model: 'modelName32',
category_id: 41,
colour: 'red',
},
]
I am completely stuck, any help is appreciated. Thank you.
you can use flatMap and map
What flatMap does is if the returned array of map looks like
[
[{...1},{...2}],
[{...3},{...4}]
]
it will flatten it and give
[
{...1},{...2},
{...3},{...4}
]
let products_row = [{id: 1,category_id: 11,options: {'modelName1': {size: '2 feet',colour: 'red',is_new: true},'modelName2': {size: '4 feet',colour: 'black',is_new: true},}},{id: 2,category_id: 21,options: {'modelName11': {size: '2 feet',colour: 'white',is_new: false},'modelName12': {size: '4 feet',colour: 'white',is_new: false},}},{id: 3,category_id: 31,options: {'modelName21': {size: '8 feet',colour: 'white',is_new: false},'modelName22': {size: '4 feet',colour: 'black',is_new: true},}},{id: 4,category_id: 41,options: {'modelName31': {size: '8 feet',colour: 'red',is_new: true},'modelName32': {size: '8 feet',colour: 'red',is_new: true},}}]
let x = products_row.flatMap(({options,...rest}) => Object.entries(options).map(([k,v]) => ({...v,...rest,model:k})))
console.log(x)
It is quite hard to analyze your solution and reason about your idea, so I cannot fix your code.
What you want to do is to extract options from each object and attach the rest of object, in other words you want to iterate over each option for each product row.
There are numerous ways to achieve this, you can use flatMap as #cmgchess suggested. Easier to understand is something like this:
let result = [];
products_row.forEach(({ options, ...rest }) =>
Object.values(options).forEach((b) => result.push({ ...rest, ...b })),
);

adding values in array where id's are the same

(14) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {itemId: 'F4', itemRate: 20, Amount: 20, itemName: 'Kesar pista', itemQuantity: 1}
1: {itemName: 'Vegetable manchuri', itemRate: 60, itemId: 'G5', Amount: 120, itemQuantity: 2}
2: {itemRate: 50, Amount: 50, itemQuantity: 1, itemId: 'C10', itemName: 'Dry fruit '}
3: {itemId: 'C3', itemRate: 40, itemQuantity: 1, Amount: 40, itemName: 'Butter scotch'}
4: {itemName: 'Panner sandwich + milk shake', Amount: 90, itemId: 'CS4', itemRate: 90, itemQuantity: 1}
5: {itemQuantity: 1, itemId: 'B5', itemRate: 70, Amount: 70, itemName: 'Panner burger'}
6: {itemId: 'C10', itemQuantity: 1, Amount: 50, itemName: 'Dry fruit ', itemRate: 50}
7: {itemQuantity: 2, itemName: 'American nuts', Amount: 100, itemRate: 50, itemId: 'C8'}
8: {itemName: 'Mango ', Amount: 50, itemQuantity: 1, itemId: 'C7', itemRate: 50}
9: {Amount: 40, itemId: 'C6', itemQuantity: 1, itemName: 'Choclate ', itemRate: 40}
10: {itemRate: 40, itemId: 'C3', itemQuantity: 1, Amount: 40, itemName: 'Butter scotch'}
11: {itemRate: 45, itemId: 'B1', itemName: 'Veg burger', Amount: 45, itemQuantity: 1}
12: {itemName: 'Veg cheese', Amount: 55, itemId: 'B2', itemQuantity: 1, itemRate: 55}
13: {itemName: 'Vanila', itemQuantity: 1, itemId: 'C1', Amount: 30, itemRate: 30}
length: 14
[[Prototype]]: Array(0)
I have a array. In the array there are 2 [id] values that are the same. I want to add the quantity,rate of these elements and merge the elements where the [id] are the same using javascript. I had tried following method but it shows wrong value.
let result = Object.values(this.orderDetail.reduce((c, {itemId,itemRate,itemQuantity,itemName}) => {
c[itemId] = c[itemId] || {itemId,itemRate,itemQuantity,itemName: 0};
c[itemId].itemRate += itemRate;
c[itemId].itemQuantity += itemQuantity;
c[itemId].itemName = itemName;
return c;
}, {}));
result
The issue is with the first line in the accumulator.
c[itemId] = c[itemId] || {itemId,itemRate,itemQuantity,itemName: 0};
You should assign the initial values here. This should be as below
c[itemId] = c[itemId] || { itemId, itemRate: 0, itemQuantity: 0, itemName: '', Amount: 0 };
Or else, you will be adding the first value twice to the accumulator.
Working Fiddle
const data = [{ itemId: 'F4', itemRate: 20, Amount: 20, itemName: 'Kesar pista', itemQuantity: 1 },
{ itemId: 'G5', itemName: 'Vegetable manchuri', itemRate: 60, Amount: 120, itemQuantity: 2 },
{ itemId: 'C10', itemRate: 50, Amount: 50, itemQuantity: 1, itemName: 'Dry fruit ' },
{ itemId: 'C3', itemRate: 40, itemQuantity: 1, Amount: 40, itemName: 'Butter scotch' },
{ itemId: 'CS4', itemName: 'Panner sandwich + milk shake', Amount: 90, itemRate: 90, itemQuantity: 1 },
{ itemId: 'B5', itemQuantity: 1, itemRate: 70, Amount: 70, itemName: 'Panner burger' },
{ itemId: 'C10', itemQuantity: 1, Amount: 50, itemName: 'Dry fruit ', itemRate: 50 },
{ itemId: 'C8', itemQuantity: 2, itemName: 'American nuts', Amount: 100, itemRate: 50 },
{ itemId: 'C7', itemName: 'Mango ', Amount: 50, itemQuantity: 1, itemRate: 50 },
{ itemId: 'C6', Amount: 40, itemQuantity: 1, itemName: 'Choclate ', itemRate: 40 },
{ itemId: 'C3', itemRate: 40, itemQuantity: 1, Amount: 40, itemName: 'Butter scotch' },
{ itemId: 'B1', itemRate: 45, itemName: 'Veg burger', Amount: 45, itemQuantity: 1 },
{ itemId: 'B2', itemName: 'Veg cheese', Amount: 55, itemQuantity: 1, itemRate: 55 },
{ itemId: 'C1', itemName: 'Vanila', itemQuantity: 1, Amount: 30, itemRate: 30 },
];
let result = Object.values(data.reduce((c, { itemId, itemRate, itemQuantity, itemName, Amount }) => {
const temp = { itemId, itemRate: 0, itemQuantity: 0, itemName: '', Amount: 0 };
c[itemId] = c[itemId] || temp;
c[itemId].itemRate += itemRate;
c[itemId].itemQuantity += itemQuantity;
c[itemId].itemName = itemName;
c[itemId].Amount += Amount;
return c;
}, {}));
console.log(result);
As I looked into the result, there is one extra time all values are passing into it. I guess you should try passing default values zero or an empty string to it.

auto calculate total sum based on discount amounts

I'm doing some calculations of the total cost of items in an array that would be displayed in the HTML, the total sum should be such that when making the calculations, it should consider the discount amount against each row and add up together before it sums up all the rows total to make the total sum.
data
costItems = [
{
name: 'Corn Flakes'
unitPrice: 9,
quantity: 10,
hasDiscount: false,
discountPercentage: 10
},
{
name: 'Sugar'
unitPrice: 5,
quantity: 10,
hasDiscount: true,
discountPercentage: 10
},
{
name: 'Bread'
unitPrice: 2,
quantity: 7,
hasDiscount: false,
discountPercentage: 0
},
{
name: 'Salt'
unitPrice: 1,
quantity: 4,
hasDiscount: false,
discountPercentage: 0
}
]
Current Code I have
calculateTotalSum() {
this.totalSum = this.costItems.reduce((sum, {unitPrice, quantity}) => sum += unitPrice * quantity, 0);
console.log(this.totalSum)
}
This works by calculating the total sum ignoring the discount amounts but what I want to do is to consider the discounts in there
const costItems = [
{
name: 'Corn Flakes',
unitPrice: 9,
quantity: 10,
hasDiscount: false,
discountPercentage: 10,
},
{
name: 'Sugar',
unitPrice: 5,
quantity: 10,
hasDiscount: true,
discountPercentage: 10,
},
{
name: 'Bread',
unitPrice: 2,
quantity: 7,
hasDiscount: false,
discountPercentage: 0,
},
{
name: 'Salt',
unitPrice: 1,
quantity: 4,
hasDiscount: false,
discountPercentage: 0,
},
];
const totalSum = costItems.reduce(
(sum, { unitPrice, quantity, discountPercentage }) =>
(sum += unitPrice * quantity * (1 - discountPercentage / 100)),
0,
);
console.log(totalSum);
You can use Array.prototype.reduce.
let costItems = [{
name: 'Corn Flakes',
unitPrice: 9,
quantity: 10,
hasDiscount: false,
discountPercentage: 10
},
{
name: 'Sugar',
unitPrice: 5,
quantity: 10,
hasDiscount: true,
discountPercentage: 10
},
{
name: 'Bread',
unitPrice: 2,
quantity: 7,
hasDiscount: false,
discountPercentage: 0
},
{
name: 'Salt',
unitPrice: 1,
quantity: 4,
hasDiscount: false,
discountPercentage: 0
}
];
let sum = costItems.reduce((acc, val) => acc += (val.quantity * val.unitPrice) * ((100 - val.discountPercentage) / 100), 0);
console.log(sum)

Morris.Line graph x and y axis label are not being displayed

I have a morris double line graph like this:
var lineGraph = Morris.Area({
element: 'graph_line',
xkey: 'Date',
ykeys: ['Sales', 'Revenue'],
labels: ['Sales','Revenue'],
fillOpacity: '0.7',
gridTextFamily: 'mtsRegular',
hideHover: 'auto',
lineWidth: '1px',
lineColors: ['#076178','#1ecee8'],
pointFillColors: ['#fff'],
pointStrokeColors: ['#012e42'],
data: [#Html.Raw(ViewBag.LineGraph)],
resize: true
});
And once the graph is rendered, it's missing the x and y axis labels... It looks like following:
What am I missing out here? Can someone help me out?
#Mohamed here is the content of ViewBag.LineGraph:
{ Date: '2018-08-06', Sales: 1, Revenue: 9.75 },
{ Date: '2018-08-08', Sales: 1, Revenue: 21.03 },
{ Date: '2018-08-09', Sales: 1, Revenue: 4.75 },
{ Date: '2018-08-12', Sales: 1, Revenue: 27.66 },
{ Date: '2018-08-13', Sales: 3, Revenue: 63.33 },
{ Date: '2018-08-16', Sales: 2, Revenue: 192.29 },
{ Date: '2018-08-18', Sales: 2, Revenue: 47.37 },
{ Date: '2018-08-19', Sales: 1, Revenue: 28.94 },
{ Date: '2018-08-20', Sales: 1, Revenue: 66.09 },
{ Date: '2018-08-21', Sales: 1, Revenue: 24.73 },
{ Date: '2018-08-22', Sales: 4, Revenue: 93.53 },
{ Date: '2018-08-23', Sales: 1, Revenue: 27.59 },
{ Date: '2018-08-25', Sales: 2, Revenue: 142.52 },
{ Date: '2018-08-26', Sales: 1, Revenue: 24.77 },
{ Date: '2018-08-27', Sales: 3, Revenue: 69.79 },
{ Date: '2018-08-29', Sales: 2, Revenue: 67.63 },
{ Date: '2018-08-30', Sales: 1, Revenue: 15.3 },
{ Date: '2018-09-01', Sales: 1, Revenue: 73.69 },
{ Date: '2018-09-02', Sales: 4, Revenue: 270.38 },
{ Date: '2018-09-03', Sales: 2, Revenue: 50.07 }
Working fine for me?
var lineGraph = Morris.Area({
element: 'graph_line',
xkey: 'Date',
ykeys: ['Sales', 'Revenue'],
labels: ['Sales','Revenue'],
fillOpacity: '0.7',
gridTextFamily: 'mtsRegular',
hideHover: 'auto',
lineWidth: '1px',
lineColors: ['#076178','#1ecee8'],
pointFillColors: ['#fff'],
pointStrokeColors: ['#012e42'],
data: [{ 'Date': '2018-08-06', Sales: 1, Revenue: 9.75},{ Date: '2018-08-08', Sales: 1, Revenue: 21.03},{ Date: '2018-08-09', Sales: 1, Revenue: 4.75},{ Date: '2018-08-12', Sales: 1, Revenue: 27.66},{ Date: '2018-08-13', Sales: 3, Revenue: 63.33},{ Date: '2018-08-16', Sales: 2, Revenue: 192.29},{ Date: '2018-08-18', Sales: 2, Revenue: 47.37},{ Date: '2018-08-19', Sales: 1, Revenue: 28.94},{ Date: '2018-08-20', Sales: 1, Revenue: 66.09},{ Date: '2018-08-21', Sales: 1, Revenue: 24.73},{ Date: '2018-08-22', Sales: 4, Revenue: 93.53},{ Date: '2018-08-23', Sales: 1, Revenue: 27.59},{ Date: '2018-08-25', Sales: 2, Revenue: 142.52},{ Date: '2018-08-26', Sales: 1, Revenue: 24.77},{ Date: '2018-08-27', Sales: 3, Revenue: 69.79},{ Date: '2018-08-29', Sales: 2, Revenue: 67.63},{ Date: '2018-08-30', Sales: 1, Revenue: 15.3},{ Date: '2018-09-01', Sales: 1, Revenue: 73.69},{ Date: '2018-09-02', Sales: 4, Revenue: 270.38},{ Date: '2018-09-03', Sales: 2, Revenue: 50.07}],
resize: true
});
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
<div id="graph_line" style="height: 250px;"></div>

Multiple filter conditions in Lodash

I have an Array of Objects containing product information where there are categories and colors as fields. Now, I have another array containing which categories and which colors to show.
Main Array:
products: [{
id: 1,
name: 'Product 1',
category: 'Home',
skill: 'Easy',
color: 'blue',
price: 100.00
}, {
id: 2,
name: 'Product 2',
category: 'Home',
skill: 'Intermediate',
color: 'red',
price: 120.00
}, {
id: 3,
name: 'Product 3',
category: 'Office',
skill: 'Intermediate',
color: 'green',
price: 190.00
}, {
id: 4,
name: 'Product 4',
category: 'Office',
skill: 'Advanced',
color: 'blue',
price: 260.00
}, {
id: 5,
name: 'Product 5',
category: 'Warehouse',
skill: 'Advanced',
color: 'white',
price: 321.00
}, {
id: 6,
name: 'Product 6',
category: 'Farm',
skill: 'Intermediate',
color: 'red',
price: 120.00
}, {
id: 7,
name: 'Product 7',
category: 'Space',
skill: 'Advanced',
color: 'green',
price: 150.00
}, {
id: 8,
name: 'Product 8',
category: 'Bathroom',
skill: 'Easy',
color: 'black',
price: 9.00
}],
My another array containing filter options:
selectedFilters: {
categories : ["home", "bathroom"] ,
colors : ["blue", "red"]
}
Now I want my output as:
[{
id: 1,
name: 'Product 1',
category: 'Home',
skill: 'Easy',
color: 'blue',
price: 100.00
}, {
id: 2,
name: 'Product 2',
category: 'Home',
skill: 'Intermediate',
color: 'red',
price: 120.00
}]
I tried the normal array filter method:
this.filteredProducts = this.products.filter(prod => {
// [prod.category, prod.color].some(val => this.selectedFilters.includes(val))
console.log(this.selectedFilters);
for (let i = 0; i < this.selectedFilters.length; i++) {
// console.log('Selected Category : ', this.selectedFilters[i]);
// console.log('Product Category : ', prod.category);
if (prod.category == this.selectedFilters[i]) {
console.log('Called category');
return true;
} else if (prod.color == this.selectedFilters[i]) {
console.log('Called color');
return true;
} else {
console.log('Called else');
continue;
}
}
});
How can I achieve this using array filter functions or Lodash functions?
No need for a library, use the standard .filter method to filter an array, check to see if each object's color and category is included in the selectedFilters object:
const products = [{
id: 1,
name: 'Product 1',
category: 'Home',
skill: 'Easy',
color: 'blue',
price: 100.00
}, {
id: 2,
name: 'Product 2',
category: 'Home',
skill: 'Intermediate',
color: 'red',
price: 120.00
}, {
id: 3,
name: 'Product 3',
category: 'Office',
skill: 'Intermediate',
color: 'green',
price: 190.00
}, {
id: 4,
name: 'Product 4',
category: 'Office',
skill: 'Advanced',
color: 'blue',
price: 260.00
}, {
id: 5,
name: 'Product 5',
category: 'Warehouse',
skill: 'Advanced',
color: 'white',
price: 321.00
}, {
id: 6,
name: 'Product 6',
category: 'Farm',
skill: 'Intermediate',
color: 'red',
price: 120.00
}, {
id: 7,
name: 'Product 7',
category: 'Space',
skill: 'Advanced',
color: 'green',
price: 150.00
}, {
id: 8,
name: 'Product 8',
category: 'Bathroom',
skill: 'Easy',
color: 'black',
price: 9.00
}];
const selectedFilters = {
categories : ["home", "bathroom"] ,
colors : ["blue", "red"]
};
const { categories, colors } = selectedFilters;
const filteredProducts = products.filter(({ category, color }) => (
categories.includes(category.toLowerCase()) && colors.includes(color.toLowerCase())
));
console.log(filteredProducts);

Categories