Related
I would like to have multiple arrays of objects like this.
E.g:
const pets = [
{
name: "cat",
age: 4
},
{
name: "dog",
age: 6
}
]
But I want to create it using a map. So I was trying something like this.
let pets = [];
pets.map((item) => {
return (
item.push({
name: "cat",
age: 4
}, {
name: "dog",
age: 6
})
)
})
By this method, I'm getting an empty array.
So assuming this is incorrect, how would I go on and make this through a map.
Please any help would be appreciated.
first of all map works by looping through an array but you have empty array let pets = []; so the loop doesn't even start ! that's why you are getting empty array
Secondly map essentially is a method through which we can create a new array with the help of an existing array so you have chosen a wrong way!
example of map
const fruits = ["Mango", "Apple", "Banana", "Pineapple", "Orange"];
console.log(fruits);
const uppercaseFruits = fruits.map((fruit)=>{
return fruit.toUpperCase(); // this thing will be added to new array in every iteration
});
console.log(uppercaseFruits);
but still ....
let pets = [""]; // an item so that loop can start
const myPets = pets.map((item) => {
return (
([{
name: "cat",
age: 4
},{
name: "dog",
age: 6
}])
)
})
console.log(myPets)
//Usage of map: for example
let array = [1, 2, 3, 4, 5];
let newArray = array.map((item) => {
return item * item;
})
console.log(newArray) // [1, 4, 9, 16, 25]
map will not change the original array, if you don't assign a value to it, the original array will never be affected
And if you want to get what you want you use RANDOM like this
//random String
function randomString(e) {
e = e || 32;
var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
a = t.length,
n = "";
for (i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a));
return n
}
//random Number
function GetRandomNum(Min,Max)
{
var Range = Max - Min;
var Rand = Math.random();
return(Min + Math.round(Rand * Range));
}
var num = GetRandomNum(10000,999999);
alert(num);
Then you can combine random strings and random numbers into a new Object through a function
I'm writing a function to find the least number of coins required to make a certain amount of change. See this problem
This is a Dynamic Programming problem, however, instead of using a traditional array I am trying to use an Object to memoize the results. It's called coinAmounts.
The map holds an array of the of least number of coins to make a particular sum, for example, to make an amount of 6, you need [5,1].
I have a getCoinsToMakeAmount and setCoinsToMakeAmount to edit/get values from the map. As we iterate paths, the setCoins will update our map if the path we passed it was a smaller combo of coins to make a given sum.
The base approach is a backtracking algo, and then I make use of the coinMap to memoize sums.
Edit
I believe I am missing an optimization, because the algorithm seems to work with smaller cycles, but with a larger input like this, it seems to not be great.
coins = [3,7,405,436]
sum = 8839
let combos = []
let coinAmounts = {}
let cycles = 0;
/**
* #param {number[]} coins
* #param {number} amount
* #return {number}
*/
var coinChange = function(coins, amount) {
coinAmounts = {}
combos = []
if(amount === 0) return 0;
coinChangeHelper(coins, 0, [], amount,0);
console.log(coinAmounts)
//console.log(combos);
// console.log("CYCLES: " + cycles)
if(!coinAmounts[amount]) return -1;
return coinAmounts[amount].length;
};
var coinChangeHelper = function(coins, amount, _chosen, desiredAmount, minPath){
let chosen = Object.assign([], _chosen);
cycles++;
// save the current iteration if it's better
setLowestCoinsToMakeAmount(amount, chosen);
if(amount > desiredAmount){
return false;
}
if(amount === desiredAmount){
combos.push(chosen);
return true;
}
// see if we already know how to make the amount requested
// need to do something with this chosen coins
const chosenCoins = getCoinsToMakeAmount(amount);
if(chosenCoins && chosenCoins.length < chosen.length){
return true;
}
//debug(coins, amount, chosenCoins, _chosen)
// like a backtracking algo
for(let i = minPath; i<coins.length; i++){
const coinAmount = coins[i];
// choose a coin
chosen.push(coinAmount)
coinChangeHelper(coins,amount+coinAmount, chosen, desiredAmount, i);
// unchoose the coin
chosen.pop();
}
}
// get a coin value
const getCoinsToMakeAmount = (amount, startCoin) => {
const currentCoinCount = coinAmounts[amount];
if(!currentCoinCount){
return undefined;
}
return currentCoinCount;
}
const setLowestCoinsToMakeAmount = (coinsSum, coinsChosen) =>{
if(coinsChosen.length <= 0) return;
const currentCoinCount = coinAmounts[coinsSum];
if(!currentCoinCount){
coinAmounts[coinsSum] = coinsChosen;
return;
}
if(coinsChosen.length < currentCoinCount.length){
coinAmounts[coinsSum] = coinsChosen;
}
}
// nicely print out the output
var debug = (coins, amt, memo, chosen) => {
let tabs = ''
for(let i =0; i<amt; i++){
tabs = tabs+'\t';
}
console.log(`${tabs} change([${amt}], [${memo}],[${chosen}]`)
}
For a case of (coins=[1,2,5], amount=11), the coinAmounts contain the best coin amounts to make a certain sum.
{
'1': [ 1 ],
'2': [ 2 ],
'3': [ 1, 2 ],
'4': [ 2, 2 ],
'5': [ 5 ],
'6': [ 1, 5 ],
'7': [ 2, 5 ],
'8': [ 1, 2, 5 ],
'9': [ 2, 2, 5 ],
'10': [ 5, 5 ],
'11': [ 1, 5, 5 ],
'12': [ 2, 5, 5 ],
'13': [ 1, 2, 5, 5 ],
'14': [ 2, 2, 5, 5 ],
'15': [ 5, 5, 5 ]
}
I believe you can simplify your approach and improve the accuracy of the algorithm at the same time. Creating a getCoins function, we start by sorting the available coins. We then loop, getting the highest coin amount less than or equal to the remaining total, until it is zero:
function getCoins(coins, amount) {
coins.sort((a,b) => b - a);
const result = [];
while (amount > 0) {
let nextCoin = coins.find(coin => coin <= amount);
if (nextCoin) {;
result.push(nextCoin);
amount -= nextCoin;
}
}
return result;
}
let length = 10;
const coins = [1,2,5];
for(let amount = 1; amount <= 20; amount++) {
console.log(`Amount: ${amount}, Coins:`, JSON.stringify(getCoins(coins, amount)));
}
I have big array, I want to make an autocomplete search, but I want to display only 10 results, so stop iterating through the array by the time there were found 10 results. I have made this:
let items = array.filter(r => r.indexOf(term)!=-1);
console.log(items.length) // lots of items, need to be limited to 10
It works but I don't know how to stop the array.filter by the time it reaches the desired limit.
You could use another variable to keep track of how many items matched the condition so far and always return false after the limit has been reached. Here is an example:
const arr = [1,0,2,0,3,0,4,5,6,7,8,9,10,11,12,13,14];
const filtered = arr.filter(function(item) {
if (this.count < 10 && item > 0) {
this.count++;
return true;
}
return false;
}, {count: 0});
console.log(filtered);
Here, I'm using an object {count: 0} as the context of the callback function. You can find out more about Array.filter from here
Basically you can use a generator function, which can be stopped by a self made limit, like in the below function
function *filter(array, condition, maxSize) {
if (!maxSize || maxSize > array.length) {
maxSize = array.length;
}
let count = 0;
let i = 0;
while ( count< maxSize && i < array.length ) {
if (condition(array[i])) {
yield array[i];
count++;
}
i++;
}
}
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log( Array.from( filter(array, i => i % 2 === 0, 2 ) ) ); // expect 2 & 4
So it will stop after it reaches maxSize as a parameter, and to easily return it into an array, you can use Array.from, which will iterate the iterator of the generator function
You could hand over a counter and omit any other values for filtering.
const
filter = v => v % 2,
filterMax = (fn, c) => x => c && fn(x) && c--,
max = 3,
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
result = array.filter(filterMax(filter, max));
console.log(result);
Taking the idea of Icepickle's answer a bit ahead with a loop for finding the next valid item and yield this one.
function* filterMax(array, cb, count) {
var i = 0;
while (count) {
while (i < array.length && !cb(array[i])) i++;
if (i >= array.length) return;
yield array[i++];
count--;
}
}
const
filter = v => v % 2,
max = 3,
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(...filterMax(array, filter, max));
You can't break from Array.prototype.filter method. It will loop over every element. You can use a simple for loop and break when 10 items are found
const items = []
for (const value of array) {
if (value.includes(term))
items.push(value)
if (items.length === 10)
break;
}
Just for the trick :
EDIT : To clarify this code will pick the 10 first even number of the list
let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
const result = array.reduce((temp, value) => {
if(value%2==0 && temp.length<10)
temp.push(value);
return temp;
}, []);
console.log(result);
var data = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14"]
var limited = data.filter((val,i)=>i<10)
console.log(limited)
You can do this just simple add .Slice(0,NO_OF_ELE_WANT)
eg. finding first two even no
[1,2,3,4,5,6,7,8,9,10].filter((e)=> e%2==0).slice(0,2)
Answer : let items = array.filter(r => r.indexOf(term)!=-1).slice(0,10);
I wrote a library that's handy for this sort of thing.
Here's how I'd find the first 100 numbers that start with the character "1"
const {blinq, range} = window.blinq;
//create a large array of strings to search
const arrToBeSearched = range(0,10000)
.select(x => `${x}`)
.toArray()
const query = blinq(arrToBeSearched)
.where(x => x.startsWith("1"))
.takeWhile((x, i) => i < 100)
const result = [...query] //no calculation until we materialize on this line
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/blinq"></script>
I know its a bit late, but here's for the new comers!
// we'll create a function which will take two arguments
// first argument would be your original array which your want to filter from
// second argument would be the number of results you want the filter to return
const limitedArray = (originalArray, limit) => {
let newArray = [];
for (let item of originalArray) {
if (newArray.length >= limit) break;
//your code here
//in my case i'll jush push in to the array
newArray.push(item)
}
return newArray;
};
//---------------->ignore v<-------------------
//the above function would return an array so in other words we can see this function as an array
const array = [1, 2, 3, 4, 5, 6, 'cascas', 'ascasc', 9, 10, 'ascs'];
console.log(limitedArray(array, 4));
//similarly
limitedArray(array, 4).forEach(item => {
console.log(item)
})
You can define your custom method on Array.prototype which will take 2 arguments. A callback and a max elements that result array will contain.
The code below gets the first 3 odd numbers from array.
function filterUpto(callback,max){
let len = this.length
let res = [];
let i = 0;
while(res.length < max && i < len){
if(callback(this[i],i,this)) res.push(arr[i])
i++
}
return res;
}
Object.defineProperty(Array.prototype,'filterUpto',{
value:filterUpto
})
let arr = [1,2,3,4,5,6,7,8,9,10];
console.log(arr.filterUpto(x => x % 2,3)); //first three odd numbers
Here is another possible solution, pretty straightforward, using Array.from:
const arr = [
"foo",
"bar",
"foobar",
"baz",
"foobaz",
"artefact",
"mortar",
"bar",
"arity",
"mark",
"car",
"dare",
"arbitrary",
"tar",
"jar",
"war",
];
const filterWithLimit = (arr, value, length) =>
Array.from(
{ length },
function () {
return arr
.slice(this.index++)
.find((option, i) => (this.index += i, option.includes(value)));
},
{ index: 0 }
);
console.log(filterWithLimit(arr, "ar", 10));
Here is a short solution which doesn't continue searching after the limit is reached:
function filter_n(array, limit, test) {
let ret = []
array.find((x)=> test(x) && ret.push(x)>=limit )
return ret
}
when test(x) is true, it calls ret.push(x) (which adds x to ret and outputs the length of ret)
then, once ret's length is >= limit, the inner function returns true, and find stops looping because it "found" a result
I have mapsOrder array and mapsData array of objects:
let mapsOrder = [1,2,1,3];
let mapData = [
{
id: 1,
gates: [
{
toId: 2,
coords: {
x: 2,
y: 42
}
},
{
toId: 3,
coords: {
x: 9,
y: 4
}
}
]
},
{
id: 2,
gates: [
{
toId: 1,
coords: {
x: 6,
y: 5
}
}
]
},
{
id: 3,
gates: [
{
toId: 1,
coords: {
x: 2,
y: 1
}
}
]
}
]
What I want to achieve is in loop basing on mapsOrder where mapsOrder array values are ids in mapData, designate gates to next map.
So we have loop that iterate 4 times and when:
loop index is 1 current map is 1 next map is 2 and gates to next are coords: { x: 2, y: 42 }
loop index is 2 current map is 2 next map is 1 and gates to next are coords: { x: 6, y: 5 }
loop index is 3 current map is 1 next map is 3 and gates to next are coords: { x: 9, y: 4 }
loop index is 4 current map is 3 next map is 1 and gates to next are coords: { x: 2, y: 1 }
last loop iteration see next map as first of mapsOrder array. I tried to do it myself by first determineting the id of next map like so:
for(let i = 0; i < mapsOrder.length; i++) {
let nextMap;
let currentMapId = mapData[mapsOrder[i] - 1].id;
if(i === mapsOrder.length - 1) {
nextMap = mapData[0].id
} else {
nextMapId = mapData[mapsOrder[i]].id;
}
console.log('Current map is: ', currentMapId, 'and the next map id is:', nextMapId)
console.log('break-----')
}
but this console incorrect ids, demo
If you don't care about the original array then just use shift to get the next gate (shift will remove the gate from the array thus the next gate will be available when the object is encountered again). Use find to find the object from the array:
let result = mapsOrder.map(id =>
mapData.find(o => o.id == id).gates.shift().coords
);
You may want to check if find actually finds something and the gates array contains something before using shift, here is a safer way:
let result = mapsOrder.map(id => {
let obj = mapData.find(o => o.id == id);
if(obj && obj.gates.length) { // if we found an object with the same id and that object still have gates
return obj.gates.shift().coords; // return the coords of the first gate and remove the gate from the array
} // otherwise, throw an error or something
});
No altering:
Instead of using shift from the previous example, we'll just use an object to track the gate index from the gates array:
let nextGateIndex = Object.create(null); // create a prototypeless object to track the next gate index for each object
let result = mapsOrder.map(id => {
let obj = mapData.find(o => o.id == id);
let index;
if(nextGateIndex[id] == undefined) {
index = 0;
} else {
index = nextGateIndex[id] + 1;
}
nextGateIndex[id] = index;
if(obj && index < obj.gates.length) {
return obj.gates[index].coords;
} // throw error or something
});
If follow your description your loop should look like. Seems that you wand to use id and toId but using array indexes. It can be a good idea to replace arrays with objects.
Demo
for(let i = 0; i < mapsOrder.length; i++) {
let nextMap;
let currentMapId = mapsOrder[i];
if(i === mapsOrder.length - 1) {
nextMapId = mapsOrder[0]
} else {
nextMapId = mapsOrder[i + 1];
}
let filteredMapData = mapData.filter(f => f.id == currentMapId);
let filteredGates = filteredMapData.length > 0 ? filteredMapData[0].gates.filter(f => f.toId == nextMapId) : [];
console.log('Current map is: ', currentMapId, 'and the next map id is:', nextMapId, 'gates:', filteredGates.length == 0 ? "no gates": filteredGates[0].coords)
console.log('break----')
}
I would recommend the filter() function for javascript arrays as it is super quick. This function will return an array filled with items from original matching some criteria (in this case, objects having the desired id).
for (let i = 0; i < mapsOrder.length; i++) {
console.log(mapData.filter(mapDataItem => mapDataItem.id === mapsOrder[i]))
}
I have an object in javascript like this:
{ "a":4, "b":0.5 , "c":0.35, "d":5 }
Is there a fast way to get the minimum and maximum value among the properties without having to loop through them all? because the object I have is huge and I need to get the min/max value every two seconds. (The values of the object keeps changing).
Update: Modern version (ES6+)
let obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
let arr = Object.values(obj);
let min = Math.min(...arr);
let max = Math.max(...arr);
console.log( `Min value: ${min}, max value: ${max}` );
Original Answer:
Try this:
let obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
var arr = Object.keys( obj ).map(function ( key ) { return obj[key]; });
and then:
var min = Math.min.apply( null, arr );
var max = Math.max.apply( null, arr );
Live demo: http://jsfiddle.net/7GCu7/1/
There's no way to find the maximum / minimum in the general case without looping through all the n elements (if you go from, 1 to n-1, how do you know whether the element n isn't larger (or smaller) than the current max/min)?
You mentioned that the values change every couple of seconds. If you know exactly which values change, you can start with your previous max/min values, and only compare with the new ones, but even in this case, if one of the values which were modified was your old max/min, you may need to loop through them again.
Another alternative - again, only if the number of values which change are small - would be to store the values in a structure such as a tree or a heap, and as the new values arrive you'd insert (or update) them appropriately. But whether you can do that is not clear based on your question.
If you want to get the maximum / minimum element of a given list while looping through all elements, then you can use something like the snippet below, but you will not be able to do that without going through all of them
var list = { "a":4, "b":0.5 , "c":0.35, "d":5 };
var keys = Object.keys(list);
var min = list[keys[0]]; // ignoring case of empty list for conciseness
var max = list[keys[0]];
var i;
for (i = 1; i < keys.length; i++) {
var value = list[keys[i]];
if (value < min) min = value;
if (value > max) max = value;
}
You could try:
const obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
const max = Math.max.apply(null, Object.values(obj));
console.log(max) // 5
min and max have to loop through the input array anyway - how else would they find the biggest or smallest element?
So just a quick for..in loop will work just fine.
var min = Infinity, max = -Infinity, x;
for( x in input) {
if( input[x] < min) min = input[x];
if( input[x] > max) max = input[x];
}
// 1. iterate through object values and get them
// 2. sort that array of values ascending or descending and take first,
// which is min or max accordingly
let obj = { 'a': 4, 'b': 0.5, 'c': 0.35, 'd': 5 }
let min = Object.values(obj).sort((prev, next) => prev - next)[0] // 0.35
let max = Object.values(obj).sort((prev, next) => next - prev)[0] // 5
You can also try with Object.values
const points = { Neel: 100, Veer: 89, Shubham: 78, Vikash: 67 };
const vals = Object.values(points);
const max = Math.max(...vals);
const min = Math.min(...vals);
console.log(max);
console.log(min);
// Sorted
let Sorted = Object.entries({ "a":4, "b":0.5 , "c":0.35, "d":5 }).sort((prev, next) => prev[1] - next[1])
>> [ [ 'c', 0.35 ], [ 'b', 0.5 ], [ 'a', 4 ], [ 'd', 5 ] ]
//Min:
Sorted.shift()
>> [ 'c', 0.35 ]
// Max:
Sorted.pop()
>> [ 'd', 5 ]
You can use a reduce() function.
Example:
let obj = { "a": 4, "b": 0.5, "c": 0.35, "d": 5 }
let max = Object.entries(obj).reduce((max, entry) => entry[1] >= max[1] ? entry : max, [0, -Infinity])
let min = Object.entries(obj).reduce((min, entry) => entry[1] <= min[1] ? entry : min, [0, +Infinity])
console.log(max) // ["d", 5]
console.log(min) // ["c", 0.35]
Here's a solution that allows you to return the key as well and only does one loop. It sorts the Object's entries (by val) and then returns the first and last one.
Additionally, it returns the sorted Object which can replace the existing Object so that future sorts will be faster because it will already be semi-sorted = better than O(n). It's important to note that Objects retain their order in ES6.
const maxMinVal = (obj) => {
const sortedEntriesByVal = Object.entries(obj).sort(([, v1], [, v2]) => v1 - v2);
return {
min: sortedEntriesByVal[0],
max: sortedEntriesByVal[sortedEntriesByVal.length - 1],
sortedObjByVal: sortedEntriesByVal.reduce((r, [k, v]) => ({ ...r, [k]: v }), {}),
};
};
const obj = {
a: 4, b: 0.5, c: 0.35, d: 5
};
console.log(maxMinVal(obj));
To get the keys for max and min
var list = { "a":4, "b":0.5 , "c":0.35, "d":5 };
var keys = Object.keys(list);
var min = keys[0]; // ignoring case of empty list for conciseness
var max = keys[0];
var i;
for (i = 1; i < keys.length; i++) {
var value = keys[i];
if (list[value] < list[min]) min = value;
if (list[value] > list[max]) max = value;
}
console.log(min, '-----', max)
For nested structures of different depth, i.e. {node: {leaf: 4}, leaf: 1}, this will work (using lodash or underscore):
function getMaxValue(d){
if(typeof d === "number") {
return d;
} else if(typeof d === "object") {
return _.max(_.map(_.keys(d), function(key) {
return getMaxValue(d[key]);
}));
} else {
return false;
}
}
Using the lodash library you can write shorter
_({ "a":4, "b":0.5 , "c":0.35, "d":5 }).values().max();
var newObj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
var maxValue = Math.max(...Object.values(newObj))
var minValue = Math.min(...Object.values(newObj))
obj.prototype.getMaxinObjArr = function (arr,propName) {
var _arr = arr.map(obj => obj[propName]);
return Math.max(..._arr);
}
This works for me:
var object = { a: 4, b: 0.5 , c: 0.35, d: 5 };
// Take all value from the object into list
var valueList = $.map(object,function(v){
return v;
});
var max = valueList.reduce(function(a, b) { return Math.max(a, b); });
var min = valueList.reduce(function(a, b) { return Math.min(a, b); });
If we are sorting date time value then follow the below described procedure
const Obj = {
"TRADE::Trade1": {
"dateTime": "2022-11-27T20:17:05.980Z",
},
"TRADE::Trade2": {
"dateTime": "2022-11-27T20:36:10.659Z",
},
"TRADE::Trade3": {
"dateTime": "2022-11-27T20:28:10.659Z",
}
}
const result = Object.entries(Obj).sort((prev, next) => new Date(prev[1].dateTime) - new Date(next[1].dateTime))
console.log(result)