Pushing spliced items returns nested array - javascript

I am trying to push 3 random items from an array into a new array. I use splice() to grab an item and remove it from the old array. When I push() the items, I would like to get them back in a single array.
For example:
["b", "f", "a"]
This is my code:
const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
let newletters = [];
for (let i = 0; i < 3; i++) {
newletters.push(letters.splice(Math.floor(Math.random() * letters.length), 1));
}
console.log(newletters);
It seems like I am pushing the spliced items as arrays into the new array, is there a way to fix this?
[
[
"b"
],
[
"f"
],
[
"a"
]
]

You could spread ... the array from Array#splice.
Or take the first element with and index.
letters.splice(Math.floor(Math.random() * letters.length)[0]
const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
let newletters = [];
for (let i = 0; i < 3; i++) {
newletters.push(...letters.splice(Math.floor(Math.random() * letters.length), 1));
}
console.log(newletters);

You can use the function Array.prototype.concat instead.
const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
let newletters = [];
for (let i = 0; i < 3; i++) {
newletters = newletters.concat(letters.splice(Math.floor(Math.random() * letters.length), 1));
}
console.log(newletters);

Use the ... operator inside the push statement.
const letters = ['a', 'b', 'c', 'd', 'e'];
const newLetters = []
newLetters.push(...letters.splice(1, 2)) // Equal to newLetters.push('b', 'c')
console.log(newletters)

const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
let newletters = [];
for (let i = 0; i < 3; i++) {
newletters.push(letters.splice(Math.floor(Math.random() * letters.length), 1));
}
console.log(newletters.flat());

Related

I just want to sort my words from array alphabetically by 1st letter and then by 2nd letter according to my given pattern which matched by 1st letter

♦ pattern:
e,b,c,d,i,f,g,h,o,j,k,l,m,n,u,p,q,r,s,t,a,v,w,x,y,z
I want to sort my words from arr alphabetically by 1st letter and then by 2nd letter of a similar word matched by 1st letter according to my given pattern.
['aobcdh', 'aibcdh', 'aabcdh', 'aacbdh', 'cfghjd', 'cighjd']
♦ output should be:
['aibcdh', 'aobcdh', 'aabcdh', 'aacbdh', 'cighjd', 'cfghjd' ]
♦ or:
aibcdh
aobcdh
aabcdh
aacbdh
cighjd
cfghjd
My Code here:
let pattern = ['e', 'b', 'c', 'd', 'i', 'f', 'g', 'h', 'o', 'j', 'k', 'l', 'm', 'n', 'u', 'p', 'q', 'r', 's', 't', 'a', 'v', 'w', 'x', 'y', 'z']
let arr = ['aobcdh', 'aibcdh', 'aabcdh', 'aacbdh', 'cfghjd', 'cighjd']
let arrSorted = arr.sort() //Natural sorting
console.log(arrSorted)
// output in array
const newArr = arrSorted.sort((a, b) => pattern.indexOf(a[1]) - pattern.indexOf(b[1]))
console.log(newArr) //Sorted by its 2nd character with given pattern
// single output without array
for (let i = 0; i < pattern.length; i++) {
for (let j = 0; j < arrSorted.length; j++) {
if (pattern[i] === arrSorted[j][1]) {
console.log(arrSorted[j]) //Sorted by its 2nd character with given pattern
}
}
}
You could sort the first by string and the second by custom value.
const
pattern = 'ebcdifghojklmnupqrstavwxyz',
array = ['aobcdh', 'aibcdh', 'aabcdh', 'aacbdh', 'cfghjd', 'cighjd'],
order = Object.fromEntries(Array.from(pattern, (l, i) => [l, i + 1]));
array.sort((a, b) =>
a[0].localeCompare(b[0]) ||
order[a[1]] - order[b[1]]
);
console.log(array);

Looping through nested arrays and reordering them in JavaScript

I am trying to loop through nested arrays and reorder them into new nested arrays. For example, take [[a,b,c,d], [e,f,g,h], [i,j,k,l]] and change it into [[a,e,i], [b,f,j], [c,g,k], [d,h,l]]
let rowArr = [[a,b,c,d], [e,f,g,h], [i,j,k,l]];
let newRowArr = [];
let length = rowArr.length;
for(let i = 0; i<length; i++){
for(let j = 0; j<rowArr.length; j++){
newRowArr.push(rowArr[i][j]);
j+=rowArr.length;
}
console.log(newRowArr) //I get only [a,e,i]
I am missing something obvious but why won't it loop the additional times to push the other letters into the array?
You could just use the nested loop where i and j are names for outer in inner index names and then use them to add to new array as result[j][i] = current inner loop value
let arr = [
['a', 'b', 'c', 'd'],
['e', 'f', 'g', 'h'],
['i', 'j', 'k', 'l']
];
const result = []
arr.forEach((a, i) => {
a.forEach((e, j) => {
if (!result[j]) result[j] = []
result[j][i] = e
})
})
console.log(result)
You can use Array.prototype.map:
let rowArr = [['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'j', 'k', 'l']];
let newRowArr = [];
let arraySize = 4;
const arrayColumn = (arr, n) => arr.map(x => x[n]);
for (let i = 0; i < arraySize; i++) {
newRowArr.push(arrayColumn(rowArr, i));
}
console.log(newRowArr);

Find index of last matching occurrence

I've got array of variables and next variable which I want to add alphabetically. It goes A-Z and after that AA, AB, AC etc..
so in when next variable is E I want to add it at the end of letters with length=1, if next variable would be AC I'd add it at the end on letters with length=2 etc. I tried to do it with findIndex, but it returns the first occurrence, not the last one and lastIndexOf accepts value while in my case it should be the last element with given length.
let variables = ['A', 'B', 'C', 'D', 'AA', 'AB'];
const nextVariable = 'E';
const idx = variables.findIndex(x => x.length === nextVariable.length);
variables.splice(idx, 0, nextVariable);
console.log(variables);
// should be ['A', 'B', 'C', 'D', 'E', 'AA', 'AB']
You can just look for the first variable which is longer than the variable to insert, and if it doesn't exist (findIndex returns -1), add to the end of the array:
let variables = ['A', 'B', 'C', 'D', 'AA', 'AB'];
let nextVariable = 'E';
let idx = variables.findIndex(x => x.length > nextVariable.length);
variables.splice(idx < 0 ? variables.length : idx, 0, nextVariable);
// should be ['A', 'B', 'C', 'D', 'E', 'AA', 'AB']
console.log(variables);
nextVariable = 'AC';
idx = variables.findIndex(x => x.length > nextVariable.length);
variables.splice(idx < 0 ? variables.length : idx, 0, nextVariable);
// should be ['A', 'B', 'C', 'D', 'E', 'AA', 'AB', 'AC']
console.log(variables);
let variables = ['A', 'B', 'C', 'D', 'AA', 'AB'];
const nextVariable = 'E';
variables[variables.length] = nextVariable
variables = variables.sort((x,y) => x.length<y.length ? -1 : x.length==y.length ? x.localeCompare(y) : 1)
console.log(variables);
You can use a custom sort function and test the alphabetical order and length of each value.
function mySort(a, b) {
if(a.length == b.length) {
return a.localeCompare(b);
} else {
return a.length - b.length;
}
}
The you can use this function to sort the array after a new value has been added:
variables.sort(mySort);

Reorder the objects in the array

I have arrays as following
var A = ['C', 'D', 'E', 'F', 'G'];
var B = [3, 0, 4, 1, 2];
I need to rearrange array A with the given index values in array B. My solution to the problem is following
function reArrange(A,B){
var num;
var letter;
for(var i = 0; i < A.length; i++){
num = B[i];
letter = A[i];
A[num] = letter;
}
return A;
}
reArrange(A, B);
I get an output of ['D', 'C', 'E', 'C', 'E'] when it should be ['D', 'F', 'G', 'C', 'E']
Hope this will help.
var A = ['C', 'D', 'E', 'F', 'G'];
var B = [3, 0, 4, 1, 2];
var C = []
function reArrange(A,B){
var num;
var letter;
for(var i = 0; i < A.length; i++){
num = B[i];
letter = A[i];
C[num] = letter;
}
return C;
}
reArrange(A, B);
console.log(C)
You could use the second array for the indices for assinging the actual value of the given array.
var array = ['C', 'D', 'E', 'F', 'G'],
order = [3, 0, 4, 1, 2],
result = order.reduce((r, a, i) => (r[a] = array[i], r), []);
console.log(result); // ['D', 'F', 'G', 'C', 'E']
Simple and short
var A = ['C', 'D', 'E', 'F', 'G'];
var B = [3, 0, 4, 1, 2];
function reorderAB(first, second){
var result= new Array();
for(var i=0;i<second.length;i++){
result[second[i]]=first[i];
}
console.log(result);
}
reorderAB(A,B);
The problem is that you replaced array A with new value.
Example with the first i in your loop.
i = 0, num = 3 and letter = C
The original A[3] = F
Then you assign A[num] = letter, mean that A[3] (F) has new value/replaced C and so on.
You can create a Map from B -> A and then order the keys accordingly to output your expected array, however I am not sure what use case you are using it for.
const A = ['C', 'D', 'E', 'F', 'G'];
const B = [3, 0, 4, 1, 2];
let bToA = new Map();
B.forEach((a, i) => bToA.set(a, A[i]))
const final = [...bToA.keys()].sort().map(x => bToA.get(x))
console.log(final);

How to get all unique elements in for an array of array but keep max count of duplicates

The question doesn't make much sense but not sure how to word it without an example. If someone can word it better, feel free to edit it.
Let's say I have an array of arrays such as this:
[ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ]
I would like the output to be:
['a', 'a', 'b', 'b', 'b', 'c', 'd', 'e']
Not sure if there is an easy way to do this in javascript/jquery/underscore. One way I could think of is to look through each of these arrays and count up the number of times each element shows up and keep track of the maximum amount of times it shows up. Then I can recreate it. But that seems pretty slow considering that my arrays can be very large.
You need to:
Loop over each inner array and count the values
Store each value and its count (if higher than current count) in a counter variable
In the end, convert the value and counts into an array
Following code shows a rough outline of the process. Remember to replace .forEach and for..in with appropriate code:
var input = [['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e']],
inputCount = {};
input.forEach(function(inner) {
var innerCount = {};
inner.forEach(function(value) {
innerCount[value] = innerCount[value] ? innerCount[value] + 1 : 1;
});
var value;
for (value in innerCount) {
inputCount[value] = inputCount[value] ? Math.max(inputCount[value], innerCount[value]) : innerCount[value];
}
});
console.log(inputCount);
// Object {a: 2, b: 3, c: 1, d: 1, e: 1}
After messing around, I found a solution but not sure if I like it enough to use. I would probably use it if I can't think of another one.
I would use underscorejs countBy to get the count of all the elements.
var array = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var count = _.map(array, function(inner) {
return _.countBy(inner, function(element) {
return element;
});
});
var total = {};
_.each(_.uniq(_.flatten(array)), function(element) {
var max = _.max(count, function(countedElement) {
return countedElement[element];
});
total[element] = max[element];
});
console.log(total); // {a: 2, b: 3, c: 1, d: 1, e: 1}
Then I would recreate the array with that total.
Here is example of simple nested loop approach:
var input = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
var countMap = {};
// iterate outer array
for (i=0; i < input.length; i++) {
// iterate inner array
for (j=0; j < input[i].length; j++) {
// increment map counter
var value = input[i][j];
if (countMap[input[i][j]] === undefined) {
countMap[value] = 1;
} else {
countMap[value]++;
}
}
}
console.log(countMap); // output such as {'a':2, 'b':4, 'c':1, 'd':1, 'e':1}
Not the most efficient solution but it should describe you the process:
var big = [ ['a', 'a', 'b', 'c'], [], ['d', 'a'], ['b', 'b', 'b', 'e'] ];
function map(arr){
var map = {}
for (var i=arr.length-1; i>-1; i--){
if(arr[i] in map) map[arr[i]]++;
else map[arr[i]] = 1;
}
return map;
}
function reduce(matrix){
var arrMap = {};
for (var i=matrix.length-1; i>-1; i--){
var arrRes = map(matrix[i]);
for (var key in arrRes){
if( !arrMap[key] || arrMap[key] < arrRes[key])
arrMap[key] = arrRes[key];
}
}
return arrMap;
}
function calc(matrix){
var res = [],
arrMap = reduce(matrix);
for (var key in arrMap){
while(arrMap[key] > 0 ){
res.push(key);
arrMap[key]--;
}
}
return res;
}
console.log(calc(big));
// Array [ "e", "b", "b", "b", "a", "a", "d", "c" ]

Categories