How to check with an array have some values - javascript

How to verify with i have only 2 or 3 numbers inside this?
without this ----> if(Array.includes(1) && !Array.includes(3))
const servicesTest: IServices[] = [
{
id: '1',
name: 'Hair',
price: 25,
icon: 'https://cdn-icons-png.flaticon.com/512/7478/7478480.png'
},
{
id: '2',
name: 'Beard',
price: 20,
icon: 'https://cdn-icons-png.flaticon.com/512/7578/7578754.png'
},
{
id: '3',
name: 'Eyebrow',
price: 15,
icon: 'https://cdn-icons-png.flaticon.com/512/2821/2821012.png'
}
]
if the client choose hair + beard this will be 40 not 45.
I´m doing this:
const name = findServices.map(services => services.name)
if (name.includes('Hair') && name.includes('Beard') && !name.includes('Eyebrown')) {
return (
setTotalDay(prevState => prevState + 40),
setTotalMonth(prevState => prevState + 40)
)
}

I would create an array of discounts like this:
const discounts = [{
price: 30,
ids: [1, 2],
}];
Then check if the array has only discounted items like this:
array.length === discount.ids.length && array.every((item) => discount.ids.includes(item.id))
const discounts = [{
price: 30,
ids: [1, 2],
}];
const discounted = [{
id: 1,
name: 'Hair',
price: 20,
},
{
id: 2,
name: 'Beard',
price: 30,
},
];
const fullPrice = [{
id: 1,
name: 'Hair',
price: 20,
},
{
id: 2,
name: 'Beard',
price: 30,
},
{
id: 3,
name: 'Tea',
price: 30,
},
];
console.log("discounted", getTotal(discounted));
console.log("full price", getTotal(fullPrice));
function getTotal(array) {
for (const discount of discounts) {
if (
array.length === discount.ids.length &&
array.every((item) => discount.ids.includes(item.id))
) {
return discount.price;
}
}
return array.reduce((sum, item) => sum + item.price, 0);
}

answering your question before the edit.
Assuming we have this array
const Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Let's say we want to check if values 2 and 3 exist.
We store the values in an array let toCheck = [2,3];
We can use function every to loop all the elements of toCheck array against the Array const
Example Follows:
const Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let toCheck = [1,2];
const allExist = toCheck.every(value => {
return Array.includes(value);
});
Hope it helps.

Related

Efficient way to get top count of an option in an array of objects

I have an array of objects like this,
[
{
user: 'A',
answers: [
{
id: 1,
score: 3,
},
{
id: 2,
score: 1,
},
...
]
},
{
user: 'B',
answers: [
...
where I have 200 users, each user answers a set of 40 questions, each question has an id and a score.
What I'm trying to do is add up each question's score. So that I can figure out which question has the highest score, which has the lowest. Aka, top question and bottom question.
What would be the best way to do this?
The current way I am doing feels a little long-winded.
const allAns = []
myList.forEach( user => allAns.push( ...user.answers ) )
const questionsScored = allAns.reduce( ( obj, cur ) => {
!obj[ cur.id ] ? obj[ cur.id ] = cur.score : obj[ cur.id ] += cur.score
return obj
}, {} )
const sortingList = []
for ( const qn in questionsScored ) {
sortingList.push( [ qn, questionsScored[ qn ] ] )
}
sortingList.sort( ( a, b ) => b[ 1 ] - a[ 1 ] )
console.log( sortingList[ 0 ], sortingList[ sortingList.length - 1 ] )
You're taking all the steps necessary so if it's working it's fine though you could replace some of your forEach() loops with available methods:
with .flatMap()
const allAns = myList.flatMap(({answers})=>answers);
and using Object.entries()
const sortingList = Object.entries(questionsScored);
const
input = [{ user: 'A', answers: [{ id: 1, score: 3, }, { id: 2, score: 1, }, { id: 3, score: 0, }] }, { user: 'B', answers: [{ id: 1, score: 2, }, { id: 2, score: 1, }, { id: 3, score: 0, }] },],
allAns = input.flatMap(({ answers }) => answers),
questionsScored = allAns.reduce((obj, cur) => {
!obj[cur.id] ? obj[cur.id] = cur.score : obj[cur.id] += cur.score
return obj
}, {}),
sortingList = Object.entries(questionsScored).sort((a, b) => b[1] - a[1]);
console.log({ max: sortingList[0], min: sortingList[sortingList.length - 1] })
Or combined into a single chained call, but it's not necessarily better.
const
input = [{ user: 'A', answers: [{ id: 1, score: 3, }, { id: 2, score: 1, }, { id: 3, score: 0, }] }, { user: 'B', answers: [{ id: 1, score: 2, }, { id: 2, score: 1, }, { id: 3, score: 0, }] },],
sortingList = Object
.entries(
input
.flatMap(({ answers }) => answers)
.reduce((obj, cur) => {
!obj[cur.id] ? obj[cur.id] = cur.score : obj[cur.id] += cur.score
return obj
}, {})
)
.sort((a, b) => b[1] - a[1]);
console.log({ max: sortingList[0], min: sortingList[sortingList.length - 1] })
If you would like to avoid the sort() call you can instead collect the low and high counts using a forEach() after the initial reduce()
const
input = [{ user: 'A', answers: [{ id: 1, score: 3, }, { id: 2, score: 1, }, { id: 3, score: 0, }] }, { user: 'B', answers: [{ id: 1, score: 2, }, { id: 2, score: 1, }, { id: 3, score: 0, }] },],
lowScore = { count: Infinity },
highScore = { count: -Infinity };
Object
.entries(
input
.flatMap(({ answers }) => answers)
.reduce((obj, cur) => {
!obj[cur.id] ? obj[cur.id] = cur.score : obj[cur.id] += cur.score
return obj
}, {})
)
.forEach(([id, count]) => {
// update low count
if (count < lowScore.count) {
lowScore.count = count;
lowScore.id = id;
}
// update high count
if (count > highScore.count) {
highScore.count = count;
highScore.id = id;
}
});
console.log({ lowScore, highScore })
// sample data
let data = [{
user: 'A',
answers: [{
id: 1,
score: 1,
},
{
id: 2,
score: 2,
},
{
id: 3,
score: 3,
},
{
id: 4,
score: 4,
},
]
},
{
user: 'B',
answers: [{
id: 1,
score: 1,
},
{
id: 2,
score: 2,
},
{
id: 3,
score: 3,
},
{
id: 4,
score: 4,
},
]
},
]
let scoreSum = []; //scoreSum to store total score of each question
let initialValue = 0;
for (let i = 0; i < 4; i++) {
let sum = data.reduce(function (accumulator, currentValue) {
return accumulator + currentValue.answers[i].score;
}, initialValue)
scoreSum.push(sum);
}
let highestScore = Math.max(...scoreSum);
let lowestScore = Math.min(...scoreSum);
// increasing index by 1 to match with question numbers
let highestScoreIndex = scoreSum.indexOf(highestScore) + 1;
let lowestScoreIndex = scoreSum.indexOf(lowestScore) + 1;
// Array.prototype.getDuplicates returns an object where the keys are the duplicate entries
// and the values are an array with their indices.
Array.prototype.getDuplicates = function () {
var duplicates = {};
for (var i = 0; i < this.length; i++) {
if (duplicates.hasOwnProperty(this[i])) {
duplicates[this[i]].push(i);
} else if (this.lastIndexOf(this[i]) !== i) {
duplicates[this[i]] = [i];
}
}
return duplicates;
};
let sameScore = scoreSum.getDuplicates();
// checking if highest score has duplicates
// and if so then updaing highest score index
//with highest score indices
if (sameScore.hasOwnProperty(highestScore)) {
highestScoreIndex = sameScore[highestScore].map((a) => a + 1);
}
// checking if lowest score has duplicates
// and if so then updaing lowest score index
//with lowest score indices
if (sameScore.hasOwnProperty(lowestScore)) {
lowestScoreIndex = sameScore[lowestScore].map((a) => a + 1);
}
console.log(`Top question no(s): ${highestScoreIndex} highest score:${highestScore}`);
console.log(`bottom question no(s): ${lowestScoreIndex} lowest score:${lowestScore}`);
I only loop once through each answer in .answers for each user using nested reduce.
The input array got three users with each three answers.
let input = [{ user: 'A', answers: [{ id: 1, score: 2, }, { id: 2, score: 1, }, { id: 3, score: 0, }] }, { user: 'B', answers: [{ id: 1, score: 2, }, { id: 2, score: 4, }, { id: 3, score: 0, }] }, { user: 'c', answers: [{ id: 1, score: 0, }, { id: 2, score: 3, }, { id: 3, score:5, }] }]
function showBestAndWorstFrom(input) {
let highestScore = {'id': 0, 'score': -Infinity};
let lowestScore = {'id': 0, 'score': Infinity};
let currentScore = 0;
let id = 0;
const LAST_USER = input.length - 1;
let answers = input.reduce((combinedObj, user, userIndex) => {
return user.answers.reduce((_answerObj, _answer) => {
id = _answer.id
currentScore = (_answerObj[id] || 0) + _answer.score;
_answerObj[id] = currentScore;
if (userIndex == LAST_USER) {
highestScore = (highestScore.score < currentScore) ? {'id': id, 'score': currentScore } : highestScore;
lowestScore = (lowestScore.score > currentScore) ? {'id': id, 'score': currentScore } : lowestScore;
}
return _answerObj;
}, combinedObj);
}, {});
// console.log(answers); // { "1": 4, "2": 8, "3": 5 }
return {highestScore, lowestScore};
}
console.log(showBestAndWorstFrom(input))

What is the most efficient way to iterate between two arrays to find matched values?

I need to find objects in array by matching array of ids. Array of ids can be longer or equal to length of array of persons. I made it with forEach loop of persons array and inside used includes method to find matched id but not sure that it is the good approach. Is there a way to optimize searching algorithm?
const ids = [1, 4, 9, 7, 5, 3];
const matchedPersons = [];
const persons = [
{
id: 1,
name: "James"
},
{
id: 2,
name: "Alan"
},
{
id: 3,
name: "Marry"
}
];
persons.forEach((person) => {
if (ids.includes(person.id)) {
matchedPersons.push(person);
}
});
console.log(matchedPersons);
codesanbox
You could take a Set with O(1) for the check.
const
ids = [1, 4, 9, 7, 5, 3],
persons = [{ id: 1, name: "James" }, { id: 2, name: "Alan" }, { id: 3, name: "Marry" }],
idsSet = new Set(ids),
matchedPersons = persons.filter(({ id }) => idsSet.has(id));
console.log(matchedPersons);
you better use filter. it does exactly what it is meant to do:
const ids = [1, 4, 9, 7, 5, 3];
const persons = [
{
id: 1,
name: "James"
},
{
id: 2,
name: "Alan"
},
{
id: 3,
name: "Marry"
}
];
const matchedPersons = persons.filter(({id}) => ids.includes(id))
console.log(matchedPersons)
you can use Map https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
const ids = [1, 4, 9, 7, 5, 3];
const matchedPersons = [];
const persons = [
{
id: 1,
name: "James"
},
{
id: 2,
name: "Alan"
},
{
id: 3,
name: "Marry"
}
];
const personsMap = new Map()
persons.forEach((person) => {
personsMap.set(person.id, person)
});
persons.forEach((person) => {
if (personsMap.has(person.id)) {
matchedPersons.push(personsMap.get(person.id));
}
});
console.log(matchedPersons);

How to sort an array of objects using another array for reference?

i want to sort an array of objects having id each object using another array that only has the ids, for example:
object = [
{id: 2, name: carlos},
{id: 1, name: maria},
{id: 4, name: juan},
{id: 3, name: pepe}, //this is the array that i want to be sorted or create a copy to return it
]
[1,2,3,4,5] //this is the array that i will use as reference to sort the first one
the final result should be:
object = [
{id: 1, name: maria},
{id: 2, name: carlos},
{id: 3, name: pepe},
{id: 4, name: juam}, //this is the array that i want to be sorted or create a copy to return it
]
im using two maps, but im always getting and array with undefined:
array_to_be_sorted.map((objects) => {
array_reference.map((id) => {
if (objects.id === id) {
return {...objects}
}
}
}
im using map cause think is the best way for bigs array, because im building a music player, so dont know how many tracks the does the user has
You could use Array.prototype.sort() method to get the result.
const data = [
{ id: 2, name: 'carlos' },
{ id: 1, name: 'maria' },
{ id: 4, name: 'juan' },
{ id: 3, name: 'pepe' },
];
const order = [1, 2, 3, 4, 5];
data.sort((x, y) => order.indexOf(x.id) - order.indexOf(y.id));
console.log(data);
Another solution using Map Object which is faster than the first one.
const data = [
{ id: 2, name: 'carlos' },
{ id: 1, name: 'maria' },
{ id: 4, name: 'juan' },
{ id: 3, name: 'pepe' },
];
const order = [1, 2, 3, 4, 5];
const map = new Map();
order.forEach((x, i) => map.set(x, i));
data.sort((x, y) => map.get(x.id) - map.get(y.id));
console.log(data);
Why not just use Array.prototpye.sort()? It's easy and fast.
const pre = document.querySelector('pre');
let object = [
{id: 2, name: 'carlos'},
{id: 1, name: 'maria'},
{id: 4, name: 'juan'},
{id: 3, name: 'pepe'}
];
const criteria = [1,2,3,4,5];
pre.innerText = 'object:' + JSON.stringify(object, null, 2) + '\n\n';
object.sort((a, b) => {
return criteria[a.id] - criteria[b.id];
});
pre.innerText += 'sorted object:' + JSON.stringify(object, null, 2);
Sort an array using criteria from a second array:
<pre></pre>
You can take advantage of Schwartzian transform and sort data based on another array.
const data = [ { id: 2, name: 'carlos' }, { id: 1, name: 'maria' }, { id: 4, name: 'juan' }, { id: 3, name: 'pepe' }, ],
order = [4, 2, 3, 1, 5],
result = data.map(o => {
const index = order.indexOf(o.id);
return [index, o];
})
.sort((a, b) => a[0] - b[0])
.map(([, o]) => o);
console.log(result);

Group or chunk array with maximum sum limit

I have an array like this
const array = [{id: 1, size: 1}, {id: 2, size: 2}, {id: 3, size: 4}, {id: 4, size: 1}, {id: 5, size: 2}, {id: 6, size: 3}, ...]
I want to group or chunk this array with the maximum sum of size properties (the sum size of every indexes cannot be greater than 4),
so new array should be something like this:
const newArray = [
[{id:1, size: 1}, {id:2, size: 2}, {id:4, size: 1}],
[{id:3, size: 4}],
[{id:5, size: 3}],
[{id:6, size: 4}],
...
]
You could find the next slot by looking to the sum of each slot.
let array = [{ id: 1, size: 1 }, { id: 2, size: 2 }, { id: 3, size: 4 }, { id: 4, size: 1 }, { id: 5, size: 2 }, { id: 6, size: 3 }],
sum = 4,
result = array.reduce((r, o) => {
const temp = r.find(a => a.reduce((s, { size }) => s + size, 0) + o.size <= sum);
if (temp) temp.push(o);
else r.push([o]);
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
my way...
const array =
[ { id: 1, size: 1 }
, { id: 2, size: 2 }
, { id: 3, size: 4 }
, { id: 4, size: 1 }
, { id: 5, size: 2 }
, { id: 6, size: 3 }
// , ...
]
, szMax = array.reduce((t,c)=>Math.max(t,c.size),0)
, temp = array.map(e=>({...e}))
, result = []
;
while (temp.length > 0)
{
let sz = szMax
, nv = []
;
while( sz > 0 )
{
let idx = temp.findIndex(x=>x.size <= sz)
if (idx===-1) break
nv.push( temp[idx] )
sz -= temp[idx].size
temp.splice(idx,1)
}
result.push([...nv])
nv = []
}
console.log( result )
.as-console-wrapper{max-height:100% !important;top: 0;}

How to transform an array into an object in javascript

I have an array like this:
[
{ id: “Идент”, name: “Назв”, price: “Сто”, quantity: “Коло” },
[ 1, “продукт 1”, “400”, 5 ],
[ 2, “продукт 2”, “300”, 7 ],
[ 2, “продукт 2”, “300”, 7 ]]
How can I transform it into something like this:
{
items: [
{ name: "Хлеб", id: 1, price: 15.9, quantity: 3 },
{ name: "Масло", id: 2, price: 60, quantity: 1 },
{ name: "Картофель", id: 3, price: 22.6, quantity: 6 },
{ name: "Сыр", id: 4, price:310, quantity: 9 }
]
};
I assume that index 0:id,1:name,2:price,3:quantity. here you go,
var array = [
[12,"abc",232,2],
[12,"abc",232,2],
[12,"abc",232,2],
[12,"abc",232,2]
];
var obj = {};
obj.options = (function(array){
var e = [];
for(i in array){
t = {};
t.id = array[i][0];
t.name = array[i][1];
t.price = array[i][2];
t.quantity = array[i][3];
e.push(t);
}
return e;
})(array);
console.log(obj)
To convert an array with data to an array with objects, you could use another array with keys and iterate it for the assignment of the properties for the new objects.
var data = [{ id: 'id', name: 'name', price: 'price', quantity: 'quantity' }, [0, 'foo', 1.99, 201], [1, 'abc', 2.5, 42], [2, 'baz', 10, 99], [6, 'bar', 21.99, 1]],
keys = Object.keys(data[0]),
result = {
items: data.slice(1).map(function (a) {
var temp = {};
keys.forEach(function (k, i) {
temp[k] = a[i];
});
return temp;
})
};
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories