I am creating a card game. I am trying to loop two arrays. I am able to do it with a for loop, but I want to use forEach(). I am not getting the right results. Below is the for loop that works, and then the forEach() way I've tried:
const suits = ['Heart','Diamond','Spade','Club']
const values=['2','3','4','5','6','7','8','9','K','Q','J','A']
const deck = []
for(i = 0; i<values.length; i++){
for(x =0; x < suits.length; x++){
const card = {value: values[i], suits: suits[x]}
deck.push(card)
}
}
values.forEach((value,x) => {
suits.forEach((suit,i) => {
const card = {value: value[x], suits: suit[i]}
deck.push(card)
})
})
With your forEach you need not use index to access the value, you simply get the value from the argument for callback. However if you are using index, you need to access values[x], suits[i] instead of value[x], suit[i].
const suits = ['Heart','Diamond','Spade','Club']
const values=['2','3','4','5','6','7','8','9','K','Q','J','A']
const deck = [];
values.forEach((value,x) => {
suits.forEach((suit,i) => {
const card = {value: value, suits: suit}
deck.push(card)
})
})
console.log(deck)
Perhaps nicer than either a for loop or a forEach one is to use a technique designed to change one array into another, index by index, such as map or flatMap.
Here, creating the deck might be a one-liner:
const suits = ['Heart','Diamond','Spade','Club']
const vals = ['2','3','4','5','6','7','8','9','K','Q','J','A']
const deck = vals .flatMap (value => suits .map (suit => ({value, suit}) ))
console .log (
deck
)
Also note that there is a fairly strong tradition, at least in the U.S., of ordering the suits from low to high as "clubs, diamonds, hearts, spades". In English this is easy to remember as they are sorted alphabetically.
You don't need i or x as value, suit have the values of each array
const suits = ['Heart','Diamond','Spade','Club']
const values=['2','3','4','5','6','7','8','9','K','Q','J','A']
const deck = []
values.forEach((value) => {
suits.forEach((suit) => {
const card = {value: value, suits: suit}
deck.push(card)
document.getElementById("content").innerHTML += JSON.stringify(card) + "<br />"
})
})
<span id="content"></span>
In each iteration your arguments of forEach callbacks are ready to use in card object.
values.forEach(value => {
suits.forEach(suit => {
const card = { value, suits }
deck.push(card)
})
})
Related
Hi I have an array of objects like below:
let tbrows = [{"rowindx":0,"speciescnt":2},{"rowindx":0,"speciescnt":3},{"rowindx":1,"speciescnt":2},{"rowindx":1,"speciescnt":3}]
I want to get the maximum value of speciecnt for each row (i.e. after filtering the array) I would like it to be
let tbrows = [{"rowindx":0,"speciescnt":3},{"rowindx":1,"speciescnt":3}];
I am using the following code that I found on the web to filter an array but it only filters on one attribute of object.
const max2 = tbrows.reduce((op, item) => op = op > item.speciescnt? op : item.speciescnt, 0);
You can also using reduce() to do it
let tbrows = [{"rowindx":0,"speciescnt":2},{"rowindx":0,"speciescnt":3},{"rowindx":1,"speciescnt":2},{"rowindx":1,"speciescnt":3}]
let result = tbrows.reduce((a,c) => {
let obj = a.find(i => i.rowindx == c.rowindx)
if(!obj){
a.push(c)
}else if(c.speciescnt > obj.speciescnt){
obj.speciescnt = c.speciescnt
}
return a
},[])
console.log(result)
Turn the array into an object (right now, you're trying to turn it into just a number). Have the object be indexed by the row index, with the associated value for that row as the highest speciecnt found so far. Then you can turn the object back into an array.
const input = [{"rowindx":0,"speciescnt":2},{"rowindx":0,"speciescnt":3},{"rowindx":1,"speciescnt":2},{"rowindx":1,"speciescnt":3}];
const grouped = {};
for (const { rowindx, speciescnt } of input) {
grouped[rowindx] = Math.max(grouped[rowindx] ?? -Infinity, speciescnt);
}
const output = Object.entries(grouped)
.map(([rowindx, speciescnt]) => ({ rowindx, speciescnt }));
console.log(output);
const datafromback=[[{name:ravi}],[{}],[{}],[{}]]
I want to access ravi. Can anyone help me how can i see ravi in my console.with dealing with nested arrays
I not getting approach but i can use map to map through datafromback array but don't know how to get inside it
You can use 0 index
const datafromback = [[{ name: 'ravi' }], [{}], [{}], [{}]]
const dataFrom = (arr, nameRavi) => {
let result
arr.forEach((ele) => {
if (ele[0].name === nameRavi) result = ele[0].name
})
return result
}
console.log(dataFrom(datafromback, 'ravi'))
one possible way is to use flat first to remove nested array
const datafromback=[[{name:ravi}],[{}],[{}],[{}]]
const flatternArray = datafromback.flat() // [{name:ravi},{},{},{}]
flatternArray.map(item => {
console.log(item.name) //
})
you can do this :
const datafromback=[[{name:'ravi'}],[{}],[{}],[{}]]
const [{name}] = datafromback.find(data=>data.find(item=>item.name === 'ravi')?.name === 'ravi')
console.log(name)
You can create a recursive function if you have non-fixed dimensions array :
const handle = e => {
if (Array.isArray(e))
return e.map(handle)
else {
console.log(e.name)
}
}
handle(array)
Or if you know the dimensions, you can use nested for loops like so :
// example for 2 dimensions
for (let y = 0; y < array.length; y++)
for (let x = 0; x < array[y].length; x++)
console.log(array[y][x].name)
Hey so what you have above is a 2D object array. if you just want to console you can use a nested forEach to get the key value, like this.
datafromback.forEach(data => {
//this is the nested array that contains the objects
data.forEach(obj => {
//here you can access the actual object
if (obj?.name) console.log(obj.name);
});
});
this will return the value of key (name) if present ie ravi in your case.
you can do it like this
const datafromback = [[{ name: 'ravi' }], [{}], [{}], [{}]];
const names = [];
datafromback.map((items) => {
items.map((item) => {
if (item?.name) names.push(item?.name);
});
});
console.log(names);
so I want to find unique values from an array.
so for example I have this array:
const mainArr = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884']
so I want to find the first matching value for each unique item.
for example, in the array, I have two strings with the shape prefix, six items with the size prefix, and two items with the height prefix.
so I want to output to be something like
const requiredVal = ["shape-10983", "size-2364", "height-3399"]
I want only the first value from any set of different values.
the simplest solution will be to iterate on the list and storing what you got in a dictionary
function removeSimilars(input) {
let values = {};
for (let value of input) {//iterate on the array
let key = value.splitOnLast('-')[0];//get the prefix
if (!(key in values))//if we haven't encounter the prefix yet
values[key] = value;//store that the first encounter with the prefix is with 'value'
}
return Object.values(values);//return all the values of the map 'values'
}
a shorter version will be this:
function removeSimilars(input) {
let values = {};
for (let value of input)
values[value.splitOnLast('-')[0]] ??= value;
return Object.values(values);
}
You could split the string and get the type and use it aks key for an object along with the original string as value. At result take only the values from the object.
const
data = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884'],
result = Object.values(data.reduce((r, s) => {
const [type] = s.split('-', 1);
r[type] ??= s;
return r;
}, {}));
console.log(result);
If, as you mentioned in the comments, you have the list of prefixes already available, then all you have to do is iterate over those, to find each first element that starts with that prefix in your full list of possible values:
const prefixes = ['shape', 'size', 'height'];
const list = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884']
function reduceTheOptions(list = [], prefixes = [], uniques = []) {
prefixes.forEach(prefix =>
uniques.push(
list.find(e => e.startsWith(prefix))
)
);
return uniques;
}
console.log(reduceTheOptions(list, prefixes));
Try this:
function getRandomSet(arr, ...prefix)
{
// the final values are load into the array result variable
result = [];
const randomItem = (array) => array[Math.floor(Math.random() * array.length)];
prefix.forEach((pre) => {
result.push(randomItem(arr.filter((par) => String(par).startsWith(pre))));
});
return result;
}
const mainArr = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884'];
console.log("Random values: ", getRandomSet(mainArr, "shape", "size", "height"));
I modified the #ofek 's answer a bit. cuz for some reason the ??= is not working in react project.
function removeSimilars(input) {
let values = {};
for (let value of input)
if (!values[value.split("-")[0]]) {
values[value.split("-")[0]] = value;
}
return Object.values(values);
}
create a new array and loop over the first array and check the existing of element before in each iteration if not push it to the new array
I know how to do it without Map. It seems more logical to use Map for this task but I can't seem to implement it. Is this even possible?
So far I tied this:
function aclean(arr) {
let result = [];
let unique = new Map();
for(let i = 0; i < arr.length; i++){
let sorted = arr[i].toLowerCase().split("").sort().join("");
/*if (unique.add(sorted)) {
result.push(arr[i]);
}*/
}
return result;
}
let array = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"];
console.log(aclean(array));
The result should be: nap,teachers,ear or PAN,cheaters,era
You could loop over your array using .forEach(), and check at each iteration whether or not your Map has a key of the sorted word, if it doesn't, then you set the sorted word as the key, and the word associated with the word as the value. You can then return an array of your map's .values() to get your result:
function aclean(arr) {
let unique = new Map();
arr.forEach(word => {
let sorted = word.toLowerCase().split("").sort().join("");
if(!unique.has(sorted)) {
unique.set(sorted, word);
}
});
return [...unique.values()];
}
let array = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"];
console.log(aclean(array));
You could take a Set with the normalized (lower case, sorted) strings and return a filtered result.
function aclean(array) {
let unique = new Set();
return array.filter(s => {
let sorted = s.toLowerCase().split("").sort().join("");
if (!unique.has(sorted)) {
unique.add(sorted);
return true;
}
});
}
let array = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"];
console.log(aclean(array));
I think Set is prefect for this case. You can do it in following steps.
First make a helper function which sorts to the strings.
Then create a unique array of sorted strings using Set and map()
Then map() that array again to the value in original array which is anagram of the sorted string.
const sort = str => str.toLowerCase().split('').sort().join('')
const aclean = arr => [... new Set(arr.map(sort))].map(x => arr.find(a => sort(a) === x))
let array = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"];
console.log(aclean(array));
I am trying to split an array of integers into an array of arrays by duplicate values. The original array is composed of a list of 6 digit integers, some of these integers come in pairs, others come in groups of 3 or 4s. I'd like to get these duplicates pushed to their own arrays and have all of these arrays of duplicates composed into an array of arrays that I can later loop through.
I've looked on in the lodash library for some method or combination of but can't quite find anything that seems to work. I've also tried a few different configurations with nested for loops but also am struggling with that.
const directory = "X/";
let files = fs.readdirSync(directory);
let first6Array = [ ];
for(i=0; i< files.length; i++){
let first6 = files[i].substring(0, 6);
first6Array.push(first6);
};
console.log(first6Array);
example output of first6Array:
[ '141848',
'141848',
'141848',
'142851',
'142851',
'143275',
'143275']
I'd like to end up with something like
let MasterArray = [[141848,141848,141848],[142851,142851],[143275,143275]];
You can use new Set() to filter out the duplicates.
Then you use the unique Array and filter for every value.
const firstArray = [ '141848', '141848', '141848', '142851', '142851', '143275', '143275'];
const numberArray = firstArray.map(Number);
const masterArray = [];
const unique = new Set (numberArray); // Set {141848, 142851, 143275}
unique.forEach(u => {
masterArray.push(numberArray.filter(e => e === u));
});
console.log(masterArray);
Using lodash, you can create a function with flow:
map the items by truncating them and converting to numbers.
groupBy the value (the default).
convert to an array of arrays using values.
const { flow, partialRight: pr, map, truncate, groupBy, values } = _;
const truncate6 = s => truncate(s, { length: 6, omission: '' });
const fn = flow(
pr(map, flow(truncate6, Number)),
groupBy,
values,
);
const firstArray = [ '141848abc', '141848efg', '141848hij', '142851klm', '142851opq', '143275rst', '143275uvw'];
const result = fn(firstArray);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Use reduce to create an object of arrays, indexed by number, and push to the associated array on each iteration (creating the array at the key first if needed), then get the values of the object:
const directory = "X/";
const files = fs.readdirSync(directory);
const output = Object.values(
files.reduce((a, file) => {
const num = Number(file.slice(0, 6));
if (!a[num]) a[num] = [];
a[num].push(num);
return a;
}, {})
);
It's pretty weird to have an array of identical values, though - you might consider a different data structure like
{
'141848': 3,
'142851': 2
}
to keep track of the number of occurrences of each number:
const output = files.reduce((a, file) => {
const num = file.slice(0, 6);
a[num] = (a[num] || 0) + 1;
return a;
}, {})
To obtain exactly the result you desire, you need a nested find, something like this should works:
const directory = "X/";
let files = fs.readdirSync(directory);
let first6Array = files.reduce((acc, value)=> {
let n = +value.substr(0, 6); // assumes it can't be NaN
let arr = acc.find(nested => nested.find(item => item === n));
if (arr) {
arr.push(n);
} else {
acc.push([n]);
}
return acc;
}, []);
console.log(first6Array);
Notice that an hashmap instead, with the value and the number of occurrence, would be better, also in term of performance, but I don't think it mind since you have really few elements.
Also, it assumes the first six characters are actually numbers, otherwise the conversion would fail and you'll get NaN.
It would be safer adding a check to skip this scenario:
let n = +value.substr(0, 6);
if (isNaN(n)) {
return acc;
}
// etc