Sorting an Array with a condition - javascript

I am trying to sort this array by price. If the item is on sale then by its onSalePrice and
if it is not sale then by its price. I have my current solution below but it doesn't work. Any thoughts??
The 'lowest-price' parameter is indicating toward the value in my option field. This parameter is definitely working okay. The issue is in the conditions that I am sorting with
const products = [
{
price: 28.99,
onSalePrice: 22.99,
onSale: "True",
},
{
price: 26.99,
onSalePrice: 22.99,
onSale: "True",
},
{
price: 24.99,
onSale: "False",
},
];
if (sort === "lowest-price") {
if (products.onSale === "True") {
tempProducts = products.slice().sort((a, b) => {
return a.onSalePrice - b.onSalePrice;
});
} else if (products.onSale === "False") {
tempProducts = products.slice().sort((a, b) => {
return a.price - b.price;
});
}
}

const products = [
{
price: 28.99,
onSalePrice: 22.99,
onSale: "True",
},
{
price: 26.99,
onSalePrice: 22.99,
onSale: "True",
},
{
price: 24.99,
onSale: "False",
},
];
const getPrice = o => o.onSale==='True' ? o.onSalePrice : o.price;
let tempProducts = [...products].sort((a,b) => getPrice(a) - getPrice(b));
console.log(tempProducts);

Related

Loop over the array and display the following format

My goal is to loop over some data and get something like the following output, so if anyone can help me out it would be greatly appreciated. In order to display something like this, I tried looping something and displaying it in a loop.
let selectedOrders: {code?: string;selectedList?: [{ name: string; language: string }];
let set = new Set();
order.orders.map((list) => {
if (!set.has(list.code)) {
selectedOrders.push({
code: list.code,
selectedList: [
{
name: list.name!,
language: list.language!,
},
],
});
set.add(list.serviceCode);
return;
}
selectedOrders.push({
selectedList: [
{
name: list.name!,
language: list.language!,
},
],
});
}
});
return selectedOrders;
});
Input
{
code:"A"
name:"php"
desc:"language"
order:2
},
{
code:"A"
name:"javascript"
desc:"language"
order:1
},
Output
code: A
selectedList: [{
name:"javascript"
desc:"language"
},
{
name:"php"
desc:"language"
}]
}
let data = [
{
code: "A",
name: "php",
desc: "language",
order: 2,
},
{
code: "B",
name: "c++",
desc: "language",
order: 3,
},
{
code: "A",
name: "javascript",
desc: "language",
order: 1
}];
let result = data.reduce((acc: any[], item) => {
const { name, desc, order, code } = item;
if (acc.some((a: any) => code == a.code)) {
let obj: any = acc.find((a: any) => code == a.code)!;
obj.selectedList.push({
name, desc, order
});
} else {
acc.push({
code,
selectedList: [{ name, desc, order }]
});
}
return acc;
}, []);
console.log(result);
Just change any to your required type.

Javascript - check if certain values are in an array of objects

Say I have an array of 5 objects, each with 2 keys (eg, 'title' & 'author').
I want to check the truthiness that 3 SPECIFIC titles exist in the array.
What's the best way to do that?
I have the following... but it doesn't seem very efficient:
const books = [
{ title: 'Book1', author: 'Author1' },
{ title: 'Book2', author: 'Author2' },
{ title: 'Book3', author: 'Author3' },
{ title: 'Book4', author: 'Author4' },
{ title: 'Book5', author: 'Author5' },
];
const certainBooks = books.some((b) => b.title === 'Book2')
&& books.some((b) => b.title === 'Book3')
&& books.some((b) => b.title === 'Book5')
if (certainBooks) {
// Do stuff
}
If the values and number of titles is dynamic, it might be worth creating an index of titles in the array; something with O(1) time complexity for faster lookups
const books = [
{ title: 'Book1', author: 'Author1' },
{ title: 'Book2', author: 'Author2' },
{ title: 'Book3', author: 'Author3' },
{ title: 'Book4', author: 'Author4' },
{ title: 'Book5', author: 'Author5' },
];
const titleIndex = new Set(books.map(({ title }) => title));
const titlesExist = (...titles) =>
titles.every(title => titleIndex.has(title))
console.log("Book2, Book3, Book5:", titlesExist("Book2", "Book3", "Book5"));
console.log("Book1:", titlesExist("Book1"));
console.log("Book5, Book6:", titlesExist("Book5", "Book6"));
A more general approach would be to map the books to their titles, then check that .every one of the titles you're looking for exists.
const books = [
{ title: 'Book1', author: 'Author1' },
{ title: 'Book2', author: 'Author2' },
{ title: 'Book3', author: 'Author3' },
{ title: 'Book4', author: 'Author4' },
{ title: 'Book5', author: 'Author5' },
];
const titles = books.map(({ title }) => title);
const toFind = ['Book2', 'Book3', 'Book5'];
if (toFind.every(title => titles.includes(title))) {
console.log('do stuff');
}
If the array of books is large, you could benefit by making titles a Set instead of an array - Set#has is faster than Array#includes when there are a lot of elements.
You could loop over them
const books = [
{ title: "Book1", author: "Author1" },
{ title: "Book2", author: "Author2" },
{ title: "Book3", author: "Author3" },
{ title: "Book4", author: "Author4" },
{ title: "Book5", author: "Author5" },
];
const booksNeeded = ["Book2", "Book3", "Book4"];
for (let book of books) {
const lookForIndex = booksNeeded.findIndex(
(title) => title.toLowerCase() === book.title.toLowerCase()
);
if (lookForIndex !== -1) {
booksNeeded.splice(lookForIndex, 1);
}
if (!booksNeeded.length) {
break; // Early break if all the books has been found
}
}
if (!booksNeeded.length) {
console.log("Do Something");
} else {
console.log("Something else");
}
const books = [
{ title: 'Book1', author: 'Author1' },
{ title: 'Book2', author: 'Author2' },
{ title: 'Book3', author: 'Author3' },
{ title: 'Book4', author: 'Author4' },
{ title: 'Book5', author: 'Author5' },
];
let ops = 0;
let search = [ "Book2", "Book3", "Book4" ];
let { length } = search;
for ( let i = 0, len = books.length; length && i < len; i++ ){
ops++;
if ( search.includes(books[i].title) ){
length--;
}
}
if ( !length ){
console.log("All books found!");
} else {
console.log("Not all books found!")
}
console.log( "Number of operations: ", ops );

Reduce function works but takes too long, vue

In my Vue app, I have a reduce function that's being called within an html/vue loop and it's taking far too long; around 21 seconds
During that time, nothing renders and the page freezes temporarily
I think part of the issue is that I'm calling the computed property in a loop and it calls the reduce function each time, but I'm still unclear on a way to optimize this to quickly go through the reduce function and allow the loop to only hit the result set as opposed to reducing through each iteration.
My result set is about 12,000 records but I've only included a few in the exact structure.
What can I do here?
<script>
const reduceFunction = (rows) =>
rows .reduce(
(a, row) => {
const employee = a [row .employee] || (a [row .employee] = {dates: {}, total_categories:0, total_items: 0, area: '', group: ''})
const date = employee .dates [row .itemDate] || (employee .dates [row .itemDate] = {categories: 0, qty: 0, total_categories: 0, unavailable: 0, orders: {}})
date.categories += +row.categories_per_item * +row.qty
date.qty += +row.qty
date.total_categories = date.categories
const order = date .orders [row .order_number] || (date .orders [row .order_number] = {itemDate: '', skus: {}})
order.itemDate = row.itemDate;
const sku = order .skus [row .sku] || (order .skus [row .sku] = {categories: '', qty: '', itemDate: '', expected: '', created: '', unavailable: 0, available:0})
sku.categories += row.categories_per_item
sku.qty += row.qty
sku.itemDate = row.itemDate
sku.expected = row.shipDate
sku.created = row.created_date
sku.heir_id = row.heir_identifier
employee.total_categories += (+row.categories_per_item * +row.qty)
employee.total_items += (+row.qty)
employee.area = row.area
employee.group = row.group_name
employee.warehouse = row.warehouse
employee.locale = row.locale
const foundKit = vm.$data.kitsData.find((kit) => kit.heir_identifier === sku.heir_id)
if (foundKit) {
new_avail = 10;
if(sku.qty > new_avail){
status.status = "Not available";
date.unavailable += 1
sku.unavailable += 1
}else{
status.status = "Available"
}
}else{
status.status = "No item found"
}
return a
},
{}
);
var vm =
new Vue({
el: "#app",
data: {
rows: [
{
employee: "Adam",
sku: "A1453",
categories_per_item: "15",
area: "1",
itemDate: "2021-11-02",
qty: 37,
group_name: "managers",
warehouse: "3",
order_number: "1234",
locale: "1",
shipDate: "2020-02-02",
created_date: "2020-01-01",
heir_identifier:"ABC3"
},
{
employee: "Joan",
sku: "A1453",
categories_per_item: "15",
area: "1a",
itemDate: "2021-11-02",
qty: 17,
group_name: "managers",
warehouse: "3",
order_number: "34578",
locale: "1",
shipDate: "2020-02-02",
created_date: "2020-01-01",
heir_identifier:"ABC3"
},
{
employee: "Bill",
sku: "A1453",
categories_per_item: "15",
area: "1",
itemDate: "2021-11-03",
qty: 57,
group_name: "managers",
warehouse: "3",
order_number: "2345",
locale: "1",
shipDate: "2020-02-02",
created_date: "2020-01-01",
heir_identifier:"ABC3"
},
{
employee: "PJ",
sku: "A6512",
categories_per_item: "150",
area: "2",
itemDate: "2021-11-03",
qty: 20,
group_name: "managers",
warehouse: "3",
order_number: "34567",
locale: "1",
shipDate: "2020-02-02",
created_date: "2020-01-01",
heir_identifier:"ABC1"
}
]
},
methods: {
},
computed: {
employeeData() {
console.log('employee data')
employeeRows = reduceFunction(this.rows)
return employeeRows
console.log(employeeRows)
},
dates() {
return Array.from(Array(11), (_, i) => new Date(Date.now() + i * 86400000).toISOString().slice(0,10))
}
}
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<tr v-for="(value, employee) in employeeData" :key="employee">
<td>#{{employee}}</td>
<td v-for="date in dates" :key="date" >
<div v-for="(dateInfo, dateValue) in value.dates" :key="dateValue" >
<div v-if="dateValue == date ">
#{{ dateInfo.total_categories }}
</div>
</div>
</td>
</tr>
</div>
My approach for this problem would be to invoke reduceFunction on mounted(){}
and create another state for the array, here I called it parsedRows
So basically to avoid unnecessary re rendering.
data: {
rows: []
parsedRows: []
}
methods: {
reduceFunction(data){
//adjust your code to fit method here
}
}
mounted(){
this.parsedRows = this.reduceFunction(this.rows);
}
and then use the parsedRows on the Vue template.
Also to move the reduceFunction to methods
The main improvement I could see would be to eliminate the nested loop here:
const foundKit = vm.$data.kitsData.find((kit) => kit.heir_identifier === sku.heir_id)
Organize the kitsDat by heir_identifier first so you can look up in O(1) instead of .finding (O(n)) each time.
const kitsByHeir = new Map();
for (const kit of vm.$data.kitsData) {
kitsByHeir.set(kit.heir_identifier, kit);
}
Then do kitsByHeir.get(sku.heir_id) inside the loop.
You might also use a for loop instead of reduce (reduce is arguably not appropriate in this situation anyway)
Also, processing 12,000 records on the client-side is pretty odd. Even with the best designed code, that could take an uncomfortable amount of time in certain environments. Consider moving the processing to a server instead.

Change the values in array based on some other value in React

For example the original array is
const [leads,setLeads] = useState([
{ name:"something", otherValue:"something",stage:["Converted","Rejected","Refunded"]},
{ name:"something2", otherValue:"something2", stage:["Converted w/o demo","Rejected","Refunded"] },
{ name:"something3", otherValue:"something3",stage:["Rejected","Refunded"]}
])
Here is what should happen
Now if the stage includes Converted or Converted w/o demo a field should be added named converted with a value if true or if it does not includes either of both converted should be set to false
Basically the desired result should be
[{ name:"something", otherValue:"something",stage:["Converted","Rejected","Refunded"],converted :true},
{ name:"something2", otherValue:"something2", stage:["Converted w/o demo","Rejected"],converted: true},
{ name:"something3", otherValue:"something3",stage:["Rejected","Refunded"], converted:false}]
The value should be set using set using setLeads function
You can pass a callback function to useState where you add the additional property after processing the initial array and return the resultant array to be set into state for the first time.
For processing the array, you can use Array.prototype.map and Array.prototype.includes
Post this any update to the state will need to take care of this property update too
const arr = [
{ name:"something", otherValue:"something",stage:["Converted","Rejected","Refunded"},
{ name:"something2", otherValue:"something2", stage:["Converted w/o demo","Rejected","Refunded" },
{ name:"something3", otherValue:"something3",stage:["Rejected","Refunded"],
]
const getInitialState = () => {
return arr.map(item => {
if(item.stage.includes('Converted w/o demo') || item.stage.includes('Converted')) {
return { ...item, converted: true}
} else {
return { ...item, converted: false}
}
})
}
const [leads, setLeads] = useState(getInitialState)
const array = [
{
name: 'something',
otherValue: 'something',
stage: ['Converted', 'Rejected', 'Refunded'],
},
{
name: 'something2',
otherValue: 'something2',
stage: ['Converted w/o demo', 'Rejected', 'Refunded'],
},
{
name: 'something3',
otherValue: 'something3',
stage: ['Rejected', 'Refunded'],
},
];
array.map((data, index) => {
if (data.stage.indexOf('Converted')) {
array[index].converted = true;
} else {
array[index].converted = false;
}
});
const [leads, setLeads] = useState(array);
// if Converted value exists in array then add converted=true otherwise converted=false . You can change the value accordingly above if statement if (data.stage.indexOf('Converted'))
// output
[
{
"name": "something",
"otherValue": "something",
"stage": [
"Converted",
"Rejected",
"Refunded"
],
"converted": false
},
{
"name": "something2",
"otherValue": "something2",
"stage": [
"Converted w/o demo",
"Rejected",
"Refunded"
],
"converted": true
},
{
"name": "something3",
"otherValue": "something3",
"stage": [
"Rejected",
"Refunded"
],
"converted": true
}
]

How to earch minimal value in objects array using map() and find() methods?

Task
There is an array of objects of the form:
{
title: 'Macbook Air',
offers: [
{
seller: 'Avic',
price: 1200
},
{
seller: 'Citrus',
price: 1600
}
]
}
It is necessary to Convert to an array of objects of the form:
{
title: 'Macbook Air',
bestOffer: {
name: 'Avic',
price: 1200
}
}
Where bestOffer is an offer with a minimum price value.
Write in one line using map() and find().
Code
"use_strict";
var productList = [
{
title: "Product X1",
offers: [
{
seller: "Company X1",
price: 400
},
{
seller: "Company X2",
price: 200
},
{
seller: "Company X3",
price: 300
}
]
},
{
title: "Product Y1",
offers: [
{
seller: "Company Y1",
price: 1700
},
{
seller: "Company Y2",
price: 1600
},
{
seller: "Company Y3",
price: 1500
},
{
seller: "Company Y4",
price: 1400
}
]
},
{
title: "Product Z1",
offers: [
{
seller: "Company Z1",
price: 50
},
{
seller: "Company Z2",
price: 60
},
{
seller: "Company Z3",
price: 10
},
{
seller: "Company Z4",
price: 90
},
{
seller: "Company Z5",
price: 70
}
]
}
];
const destinations = productList.map(item =>
({
title: item.title,
bestOffer: ({
name: item.offers[0].seller, // TODO: How to implement find() method????
price: item.offers[0].price
})
})
)
console.log(destinations)
My code work for restructuring objects for new array, BUT i dont know how to implement find() method for searching minimal value. Is it possible using find() method in this case??
You can use Array.reduce() to find the best offer by price. On each iteration check if the current item's (o) price is less than the accumulator's (r) price, and take the one with the lowest.
const productList = [{"title":"Product X1","offers":[{"seller":"Company X1","price":400},{"seller":"Company X2","price":200},{"seller":"Company X3","price":300}]},{"title":"Product Y1","offers":[{"seller":"Company Y1","price":1700},{"seller":"Company Y2","price":1600},{"seller":"Company Y3","price":1500},{"seller":"Company Y4","price":1400}]},{"title":"Product Z1","offers":[{"seller":"Company Z1","price":50},{"seller":"Company Z2","price":60},{"seller":"Company Z3","price":10},{"seller":"Company Z4","price":90},{"seller":"Company Z5","price":70}]}]
const findBestOffer = ({ offers = [] }) => offers
.reduce((r, o) => o.price < r.price ? o : r)
const formatOffer = item => item ? ({
name: item.seller,
price: item.price
}) : 'none'
const destinations = productList.map(item => ({
title: item.title,
bestOffer: formatOffer(findBestOffer(item))
}))
console.log(destinations)
If you need to use Array.map() and Array.find() - map the array to the price numbers, and get the lowest one using Math.min(), and then find the item with that price:
const productList = [{"title":"Product X1","offers":[{"seller":"Company X1","price":400},{"seller":"Company X2","price":200},{"seller":"Company X3","price":300}]},{"title":"Product Y1","offers":[{"seller":"Company Y1","price":1700},{"seller":"Company Y2","price":1600},{"seller":"Company Y3","price":1500},{"seller":"Company Y4","price":1400}]},{"title":"Product Z1","offers":[{"seller":"Company Z1","price":50},{"seller":"Company Z2","price":60},{"seller":"Company Z3","price":10},{"seller":"Company Z4","price":90},{"seller":"Company Z5","price":70}]}]
const findBestOffer = ({ offers = [] }) => {
const min = Math.min(...offers.map(o => o.price))
return offers.find(o => o.price === min)
}
const formatOffer = item => item ? ({
name: item.seller,
price: item.price
}) : 'none'
const destinations = productList.map(item => ({
title: item.title,
bestOffer: formatOffer(findBestOffer(item))
}))
console.log(destinations)
Since you prefer to use FIND and MAP, I have a clearer solution for you then.
// product list
const productList = [{"title":"Product X1","offers":[{"seller":"Company X1","price":400},{"seller":"Company X2","price":200},{"seller":"Company X3","price":300}]},{"title":"Product Y1","offers":[{"seller":"Company Y1","price":1700},{"seller":"Company Y2","price":1600},{"seller":"Company Y3","price":1500},{"seller":"Company Y4","price":1400}]},{"title":"Product Z1","offers":[{"seller":"Company Z1","price":50},{"seller":"Company Z2","price":60},{"seller":"Company Z3","price":10},{"seller":"Company Z4","price":90},{"seller":"Company Z5","price":70}]}]
// Search text from Collection
function searchProduct(niddle, haystack){
const searchResult = haystack.find(item=> item['title'] === niddle);
let bestOffer;
if(searchResult){
bestOffer = getBestOffer(searchResult);
}
return bestOffer;
}
// Search for best Offer
function getBestOffer(dataInfo){
let bestOffer = {seller: null,price: null};
dataInfo['offers'].map((item, index)=>{
if(bestOffer.price === null || bestOffer.price > item.price){
bestOffer = item;
}
})
return bestOffer;
}
//run
console.log( searchProduct("Product Z1", productList) );
//output is
// Object {seller: "Company Z3", price: 10}
I hope you like it.

Categories

Resources