I have an array of array with elements for example:
var one = [1span,2span,3span,4span,5span,6span,7span];
var two = [1span,2span,3span,4span,5span,6span,7span];
var three = [1span,2span,3span,4span,5span,6span,7span];
var ...till seven.
var total = [one,two,three ..till 7]
so basically we have 7 arrays and total variable will display 7 elements for each one of all 7 arrays.
now I have a function that should populate my variables with distinct numbers from 1 to 7 on each section.
var bar = [1, 2, 3, 4, 5, 6, 7];
for(var j=0; j<total.length; j++) {
Array.from(total[j]).forEach(function(e, i, a) {
e.textContent = bar[Math.round(Math.random()*(bar.length-1))];
console.log(e,i,k);
});
}
all good my function does that but unfortunately is populating span elements with values from bar variable for each variable from total var 7 times for each and should populate just once for each variable.
So my problem is:
I want to populate each variable from total var with values from bar array just once.
The values should be randomly and unique for each variable.
You could use an copy of the given array and generate random items without repeat.
function generate(count, values) {
return Array.apply(null, { length: count }).map(function () {
var r = [],
array = values.slice();
while (array.length) {
r.push(array.splice(Math.floor(Math.random() * array.length), 1)[0]);
}
return r;
});
}
console.log(generate(7, [1, 2, 3, 4, 5, 6, 7]));
Randomize a single array
function generate(values) {
var r = [],
array = values.slice();
while (array.length) {
r.push(array.splice(Math.floor(Math.random() * array.length), 1)[0]);
}
return r;
}
console.log(generate([1, 2, 3, 4, 5, 6, 7]));
If we would like to extend the question for a general case of an N dimensional array filled with random integers then a reusable approach could be as follows;
We will use two generic functions that i like to use very much; Array.prototype.clone() and Array.prototype.shuffle(). Our arrayND function takes indefinite number of arguments. The last argument will designate the minimum (base) of the random integer to be filled. Previous arguments will give the length of each dimension. So in the particular case as we will need a 2D 7x7 matrice to be filled with random but unique numbers in each starting from 1, we shall invoke our function as arrayND(7,7,1)
Array.prototype.shuffle = function(){
var i = this.length,
j;
while (i > 1) {
j = ~~(Math.random()*i--);
[this[i],this[j]] = [this[j],this[i]];
}
return this;
};
Array.prototype.clone = function(){
return this.map(e => Array.isArray(e) ? e.clone() : e);
};
function arrayND(...n){
return n.reduceRight((p,c) => c = Array(...Array(c)).map((e,i) => Array.isArray(p) ? p.clone().shuffle() : i+p));
}
var arr = arrayND(7,7,1);
console.log(arr);
since you want these Arrays to be processed together you should put them together into a data-structure:
var spans = [ one, two, tree, ..., seven ]
now you want a random order without repetition, put the possible indices into an Array and shuffle that:
var indices = [0,1,2,3,4,5,6];
and some shuffler:
function shuffle(arr){
for(var i=arr.length, j, tmp; i-- > 1; ){
tmp = arr[j = 0|(Math.random()*i)];
arr[j] = arr[i];
arr[i] = tmp;
}
return arr;
}
now if you want the Nodes for total:
var total = shuffle(indices).map((index, n) => spans[n][index]);
at least as far as I understand your question/code/intentions.
Related
I want to know how can I add 3 different number to the 3n, 3n+1 and 3n+2 indices. I mean for example I have following array :
var arr = [1,1,1,2,2,2,3,3,3]
and then I want add the (3n)th to 5 and then I want add (3n+1)th of an array to 2 and (3n+2) to 3,
I mean the final array I want to be like following result array:
var result = [6,3,4,7,4,5,8,5,6]
and I try to do it as following code:
// arr = [1,1,1,2,2,2,3,3,3]
let res = [];
for (let i = 0; i < arr.length; i++) {
res.push([arr[i*3] * 5,
arr[(i*3)+1] *2,
arr[(i*3)+2] *3])
}
This should do the trick:
var arr = [1,1,1,2,2,2,3,3,3],
add = [5,2,3], res=[];
// result = [6,3,4,7,4,5,8,5,6]
for (let i=0;i<arr.length;i+=add.length) add.forEach((v,j)=>res[i+j]=arr[i+j]+v);
console.log(JSON.stringify(res))
An alternative and even shorter solution (similar to #Robin's answer) would be:
var arr = [1,1,1,2,2,2,3,3,3],
add = [5,2,3], res=[];
res=arr.map((v,i)=>v+add[i%add.length]);
console.log(JSON.stringify(res))
( I noticed #Nina came up with a very similar answer ...)
You can simply use map, making use of the fact that its function argument takes the current index an optional second argument:
var arr = [1,1,1,2,2,2,3,3,3];
var result = arr.map((num, idx) => {
switch (idx % 3) {
case 0:
return num + 5;
case 1:
return num + 2;
case 2:
return num + 3;
}
});
console.log(result);
You could mapp the array directly by taking a closure over an index for the values array for adding.
var array = [1, 1, 1, 2, 2, 2, 3, 3, 3],
add = [5, 2, 3],
result = array.map((i => v => v + add[i++ % add.length])(0));
console.log(...result);
I have a huge array of data that I got from PDF files. The pdfs had 10 data items per page but because it was presented in two columns the data is shuffled. The first and last item of each group of ten items are in the correct position but the rest are not.
The order is now 0,2,4,6,8,1,3,5,7,9,10,12,14,16,18,11...
and i need it to be 0,1,2,3...
I've tried looping through the array and pushing items to a new array using different if statements but just cant get it right.
Here is a function that takes the data as you get it, and two more arguments to indicate the number of columns and number of rows on a page:
function uncolumnize(data, numColumns, numRows) {
let perPage = numColumns * numRows;
return data.map((_, i) =>
data[Math.floor(i / perPage) * perPage
+ Math.floor((i % perPage) / numColumns)
+ (i % numColumns) * numRows]
);
}
let res = uncolumnize([0,2,4,6,8,1,3,5,7,9,10,12,14,16,18,11,13,15,17,19], 2, 5);
console.log(res);
It uses the map Array method, since the result (obviously) has just as many elements as the original data. The callback given to map does not use the value, but only the index. That index is used to determine the page, the row and the column. The latter two are reversed to rebuild a new index, and the data at that new index is returned.
2 columns of 10 elements per page will have groups of 10 as 10n,10n+2,10n+4,10n+6,10n+8,10n+1,10n+3,10n+5,10n+7,10n+9
There will be groups of 10 elements and one group (the last one) which will have 0-9 elements.
N = 5 //numbers of rows
len = numbers.length //numbers is the array
groups_of_2n_len = len/(2*N)
last_group_len = len%(2*N)
//For each group complete group
for(group_i = 0; group_i<groups_of_2n_len ; group_i=group_i +1)
{
//Store those 2N elements in an array
temp_array = numbers.slice(group_i*2*N,group_i*2*N + 2*N)
element = group_i*2*N
//Iterate row wise and fix the numbers
for(temp_i = 0; temp_i< N; temp_i = temp_i+1)
{
numbers[element]=temp_array[temp_i]
numbers[element+1] = temp_array[temp_i + N]
element = element+2
}
}
//For last group
if(last_group_len ==0) return
temp_array = numbers.slice(groups_of_2n_len*2*N,/*Till Last element*/)
element = groups_of_2n_len*2*N
for(temp_i = 0; temp_i< floor(last_group_len/2); temp_i = temp_i+1)
{
numbers[element]=temp_array[temp_i]
numbers[element+1] = temp_array[temp_i + floor(last_group_len/2)+last_group_len%2]
element = element+2
}
//In case of odd number of elements, no need to handle
//last element since it is already in correct place
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Example highlighted:
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
return a - b;
});
console.log(numbers);
// [1, 2, 3, 4, 5]
If numbers are in two separate arrays you can do something like this...
const array1 = [0, 4, 6, 5, 7];
const array2 = [1, 3, 2, 8, 9];
const combined = [...array1, ...array2];
console.log(combined);
I created a function that will find pairs to add the two numbers that will be equal to the sum.
function findingSum(arr, sum){
var firstElement = [];
var difference = [];
var final = [];
var convertArr = arr.map(function(item){
return parseInt(item, 10);
});
for(var i = 0; i < convertArr.length; i++){
difference.push(sum - convertArr[i]); // subtracted sum from each convertArr item
if(difference[i] + convertArr[i] === sum){ // check if convertArr item was added to difference item === sum
firstElement.push(convertArr[i]); // if so add the convertArritem to the result array
}
if(firstElement[i] + convertArr[i] == sum){
final.push(firstElement[i], convertArr[i]);
}
}
return final;
}
var addNumbers = findingSum([3, 34, 4, 12, 5, 2], 9);
console.log(addNumbers); // --> [4, 5]
So what I did is that I try to get the difference of convertArr[i] and the sum and put them in a difference variable. Then I tried to see if adding difference[i] from the original array will give me the sum. If so I'll add them on firstElement array and try to add each value to the original array and finally push them along with it's addenth if the sum was attain. So when you add this two you'll get the sum.
For some reason my logic doesn't work and it does'nt push things on both firstElement and final array. Can anyone help me with this?>
You could use a hash table for visited values.
var findingSum = function (array, s) {
var a, i,
hash = Object.create(null);
for (i = 0; i < array.length; i++) {
a = array[i];
if (hash[s - a]) {
return [s - a, a];
}
if (!hash[a]) {
hash[a] = true;
}
}
};
console.log(findingSum([3, 34, 4, 12, 5, 2], 9)); // [4, 5]
I am creating a function that takes in an array of unsorted integers and returns an array of the unique integers, sorted by frequency. However, if the integers have the same frequency, they will be returned in the original order of the input array. Here is my current function:
function uniqueUnionSorted(arr) {
counter = {};
for(var i=0; i<arr.length; i++) {
if (arr[i] in counter) {
counter[arr[i]] ++;
} else {
counter[arr[i]] = 1;
}
}
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b] - counter[a]
});
var sortedNumbers = sortedStrings.map(Number);
return sortedNumbers;
}
So for an array like this:
arr = [1, 3, 2, 1, 5, 2, 1, 4]
the function should return:
[1,2,3,5,4]
However, my function is sorting the 5 and 4 and is returning:
[1,2,3,4,5]
Please help!
The cause of this reordering is that object properties that are numerical will come out ordered when using Object.keys().
Instead of defining counter as an object, use a Map, which will retain the insertion order:
function uniqueUnionSorted(arr) {
var counter = new Map();
for(var i=0; i<arr.length; i++) {
counter.set(arr[i], (counter.get(arr[i]) || 0) + 1);
}
// Spreading the Map will produce an array of pairs
var sortedNumbers = [...counter].sort(function(a,b) {
return b[1] - a[1]; // sort by count
}).map(a => a[0]); // only keep the values, not the counts
return sortedNumbers; // Map keys retain original type, so they remain numeric
}
arr = [1, 3, 2, 1, 5, 2, 1, 4]
console.log(uniqueUnionSorted(arr));
In counter object we can also save lowest index of each element so we can keep elements with lower index earlier in sorted array.
function uniqueUnionSorted(arr) {
counter = {};
for(var i=0; i<arr.length; i++) {
if (arr[i] in counter) {
counter[arr[i]].count ++;
} else {
counter[arr[i]] = {'count' : 1, 'index' : i}; //save lowest index of element
}
}
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b].count - counter[a].count || counter[a].index - counter[b].index;
});
var sortedNumbers = sortedStrings.map(Number);
return sortedNumbers;
}
console.log(uniqueUnionSorted([1, 3, 2, 1, 5, 2, 1, 4]));
https://jsfiddle.net/anLrwwfa/4/
Here's another way you could do this using a Set object, an object to store frequency, and the original array to keep the origin intact. It's a bit longer than the current popular answer but I was in the midst of writing it, so I figured I would throw my hat in the ring.
function sortArr(arr) {
let uniqueValues = new Set();
let frequencies = new Object();
//add values to set object
arr.map((val) => uniqueValues.add(val));
//get frequencies of values
for (let val of uniqueValues) {
frequencies[val] = 0;
}
arr.map((val) => frequencies[val]++);
//sort by frequency, then sort by original placement in array
let sorted_arr = Array.from(uniqueValues).sort((a, b) => {
return frequencies[a] - frequencies[b];
}).sort((a, b) => {
return (frequencies[a] === frequencies[b]) ?
Array.from(uniqueValues).indexOf(a) - Array.from(uniqueValues).indexOf(b) :
b;
});
//return array
return sorted_arr;
};
sortArr([1, 3, 2, 1, 5, 2, 1, 4]); //1,2,3,5,4
EDIT
optimized code a bit
May add an additional condition to actually sort after the original array index if the frequency is equal:
sortedStrings = Object.keys(counter).sort(function(a,b) {
return counter[b] - counter[a] || arr.indexOf(+a)-arr.indexOf(+b)
});
http://jsbin.com/zewulanozo/edit?console
Hi I'm struggling to solve this problem. How to create a javascript function that takes any number of arrays as arguments, then returns an array of elements that only appear in one of the arrays. All items that appear in multiple arrays are removed. Getting nowhere with a solution, suspect I'm not approaching it in the right way, stumped!
Edit: the other question addresses eliminating duplicate values in one array, I need to compare x number of separate arrays and return the values that aren't duplicated between arrays. So ([5,6,7],[5,8,9]) returns [6,7,8,9].
function sym(args) {
var ans = [];
for(var i =0;i<arguments.length;i++){
var tempArr = arguments[i].filter(function(el){
var filtTrue = false;
for(var j = 0;j<arguments.length;j++){
if(Array.isArray(arguments[j]) && arguments[j] !== arguments[i]){
if(arguments[j].indexOf(el) === -1){
filtTrue = true;
}}
}
return filtTrue;
});
ans = ans.concat(tempArr);
}
return ans;
}
Here's one way to do it. The idea here is that you create a map for keeping counts of all the items in the array. You then cycle through each array, look up each value in the map and, if found, you increment its count. If not found, you set the count to 1. Then, when done with all the arrays, you collect any items that have a count of 1.
You weren't specific about what to do if an item appears more than once in the same array, but not in any other array. This first solution will not include that item (since it detects duplicates). It could be adapted (with a little more complexity) to allow that item if that was an issue (see 2nd code block below for that implementation).
function sym(/* pass one or more arrays here */) {
var ans = [], cnts = {};
//count all items in the array
for (var i = 0; i < arguments.length; i++){
arguments[i].forEach(function(item) {
if (cnts.hasOwnProperty(item)) {
// increase cnt
++cnts[item].cnt;
} else {
// initalize cnt and value
cnts[item] = {cnt: 1, val: item};
}
});
}
for (var item in cnts) {
if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
ans.push(cnts[item].val);
}
}
return ans;
}
If you want to include items that are present more than once in a single array, but not present in any other array, then you can use this slightly more complicated adaptation:
function sym(/* pass one or more arrays here */) {
var ans = [], cnts = {}, currentMap;
//count all items in the array
for (var i = 0; i < arguments.length; i++){
currentMap = {};
arguments[i].forEach(function(item) {
// if we haven't already counted this item in this array
if (!currentMap.hasOwnProperty(item)) {
if (cnts.hasOwnProperty(item)) {
// increase cnt
++cnts[item].cnt;
} else {
// initalize cnt and value
cnts[item] = {cnt: 1, val: item};
}
}
// keep track of whethere we've already counted this item in this array
currentMap[item] = true;
});
}
// output all items that have a cnt of 1
for (var item in cnts) {
if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
ans.push(cnts[item].val);
}
}
return ans;
}
Working demo: http://jsfiddle.net/jfriend00/bete5k3n/
I know this is increadibly late but this is another way to do it. Maybe not the most rigorous one but certainly creative. The method Array.symmetricDifference() expects any number of arguments and returns the symmetric difference of those arguments.
Array.prototype.symmetricDifference = function() {
var args = [];
// copy arguments into a real array and get rid of duplicates with filter
for(var i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
args[i] = args[i].filter(function(item, pos, self) {
return self.indexOf(item) == pos;
});
}
var diff = args[0];
// iterate through every arguments in args.
// concatenate the first two arguments to form a new set.
// now every number in this new set that was contained in both arguments
// from before will be contained at least twice in this new set.
for(var j = 1; j < args.length; j++) {
//sort the new set so that duplicates are next to each other.
diff = diff.concat(args[j]).sort();
var index = 0;
// now iterate through the new set and delete both duplicates if you
// find any. Otherwise proceed to the next index.
while(index < diff.length) {
// if duplicate is found delete both, otherwise look at next index.
diff[index] === diff[index + 1] ? diff.splice(index, 2) : index++;
}
}
return diff;
};
You can invoke that method on any array or create a new one and invoke it on that one like this for example:
// take any number of arrays
var a = [3, 3, 3, 2, 5];
var b = [2, 1, 5, 7];
var c = [3, 4, 6, 6];
var d = [1, 2, 3];
var e = [5, 3, 9, 8];
var f = [1];
// invoke the method on "solution" with any number of arguments
// and store it in solution.
var solution = solution.symmetricDifference(a,b,c,d,e,f);
console.log(solution); // [1, 2, 4, 5, 6, 7, 8, 9]
I hope this helps!
Finding unique items in multiple arrays
function uniqueItemsInArrays(...args){
let allItems = [];
allItems = allItems.concat(...args)
return allItems.filter(function(item, pos, self) {
return self.indexOf(item) === pos && self.indexOf(item,pos+1) === -1;
});
}
uniqueItemsInArrays( [1, 5, 1, 8, 1, 2],
[2, 2, 9, 3, 5],
[1, 4, 7, 6] );
The above code uses ES6 rest parameters to access all the arrays passed as arguments. Then using the concat() function, I am joining all the individual arrays to a single array. Finally, filter function has been used to identify and return the unique items from this array. The logic here is to find out the first index of the current item and if there are no more occurrence from the first index then we return that item.