Manipulate more javascript array based on another array - javascript

I've a strange thing to do but I don't know how to start
I start with this vars
var base = [1,1,1,2,3,5,7,9,14,19,28,40,56,114,232,330];
var sky = [0,0,0,3,4,5,6,7,8,9,10,11,12,14,16,17];
var ite = [64,52,23,38,13,15,6,4,6,3,2,1,2,1,1,1];
So to start all the 3 array have the same length and the very first operation is to see if there is a duplicate value in sky array, in this case the 0 is duplicated and only in this case is at the end, but all of time the sky array is sorted. So I've to remove all the duplicate (in this case 0) from sky and remove the corresponding items from base and sum the corresponding items on ite. So if there's duplicate on position 4,5 I've to manipulate this conditions. But let see the new 3 array:
var new_base = [1,2,3,5,7,9,14,19,28,40,56,114,232,330];
var new_sky = [0,3,4,5,6,7,8,9,10,11,12,14,16,17];
var new_ite = [139,38,13,15,6,4,6,3,2,1,2,1,1,1];
If you see the new_ite have 139 instead the 64,52,23, that is the sum of 64+52+23, because the first 3 items on sky are the same (0) so I remove two corresponding value from base and sky too and I sum the corresponding value into the new_ite array.
There's a fast way to do that? I thought a for loops but I stuck at the very first for (i = 0; i < sky.length; i++) lol, cuz I've no idea on how to manipulate those 3 array in that way
J

When removing elements from an array during a loop, the trick is to start at the end and move to the front. It makes many things easier.
for( var i = sky.length-1; i>=0; i--) {
if (sky[i] == prev) {
// Remove previous index from base, sky
// See http://stackoverflow.com/questions/5767325/how-to-remove-a-particular-element-from-an-array-in-javascript
base.splice(i+1, 1);
sky.splice(i+1, 1);
// Do sum, then remove
ite[i] += ite[i+1];
ite.splice(i+1, 1);
}
prev = sky[i];
}
I won't speak to whether this is the "fastest", but it does work, and it's "fast" in terms of requiring little programmer time to write and understand. (Which is often the most important kind of fast.)

I would suggest this solution where j is used as index for the new arrays, and i for the original arrays:
var base = [1,1,1,2,3,5,7,9,14,19,28,40,56,114,232,330];
var sky = [0,0,0,3,4,5,6,7,8,9,10,11,12,14,16,17];
var ite = [64,52,23,38,13,15,6,4,6,3,2,1,2,1,1,1];
var new_base = [], new_sky = [], new_ite = [];
var j = -1;
sky.forEach(function (sk, i) {
if (!i || sk !== sky[i-1]) {
new_ite[++j] = 0;
new_base[j] = base[i];
new_sky[j] = sk;
}
new_ite[j] += ite[i];
});
console.log('new_base = ' + new_base);
console.log('new_sky = ' + new_sky);
console.log('new_ite = ' + new_ite);

You can use Array#reduce to create new arrays from the originals according to the rules:
var base = [1,1,1,2,3,5,7,9,14,19,28,40,56,114,232,330];
var sky = [0,0,0,3,4,5,6,7,8,9,10,11,12,14,16,17];
var ite = [64,52,23,38,13,15,6,4,6,3,2,1,2,1,1,1];
var result = sky.reduce(function(r, n, i) {
var last = r.sky.length - 1;
if(n === r.sky[last]) {
r.ite[last] += ite[i];
} else {
r.base.push(base[i]);
r.sky.push(n);
r.ite.push(ite[i]);
}
return r;
}, { base: [], sky: [], ite: [] });
console.log('new base:', result.base.join(','));
console.log('new sky:', result.sky.join(','));
console.log('new ite:', result.ite.join(','));

atltag's answer is fastest. Please see:
https://repl.it/FBpo/5

Just with a single .reduce() in O(n) time you can do as follows; (I have used array destructuring at the assignment part. One might choose to use three .push()s though)
var base = [1,1,1,2,3,5,7,9,14,19,28,40,56,114,232,330],
sky = [0,0,0,3,4,5,6,7,8,9,10,11,12,14,16,17],
ite = [64,52,23,38,13,15,6,4,6,3,2,1,2,1,1,1],
results = sky.reduce((r,c,i) => c === r[1][r[1].length-1] ? (r[2][r[2].length-1] += ite[i],r)
: ([r[0][r[0].length],r[1][r[1].length],r[2][r[2].length]] = [base[i],c,ite[i]],r),[[],[],[]]);
console.log(JSON.stringify(results));

Related

Creating new array from unique elements found in array

I was given an assignment:
Finding unique elements in an array and creating a new array from these unique elements.
The professor gave us the pseudocode to code this assignment - it should be straightforward but my code is not working.
Here is my attempt:
// search for unique birthdays in the array
function find(birthdays) {
var uniqueBirthdays = [];
for (var i = 1; i <= birthdays.length; i = i + 2) {
var count = 0;
for (var j = 1; j <= birthdays.length; j = j + 2) {
if (birthdays[i] == birthdays[j]) {
count++;
}
}
if (count == 1) {
var n = uniqueBirthdays.length;
uniqueBirthdays[n] = birthdays[i - 1];
}
}
return uniqueBirthdays;
}
I have tried checking for indentation errors as well as a number of other things but can not figure out why as the array is traversed it is giving each element a count of only 1 (meaning there are no matching elements) - it does not seem to be traversing the array more than once so no elements have a count greater than 1 - even though I am using nested for loops.
I have increased the intervals by 2 because I need to compare every other element - there is a number assigned to each birthday so the array may look like:
['0001'][12/15]['0002'[03/12]...
I am brand new so I may be overlooking simple but ive tried so many things and i can not understand why this code isnt working - it is returning back all of the elements that are assigned to the birthdays instead of just the unique ones.
Any help that will point me in the right direction is very much appreciated.
You were very close, and there were just a couple mistakes. The only things that did not work were the way you wrote your for loops:
for (var i = 1; i <= birthdays.length; i = i + 2) {
Array indexes start at 0, so if you want to process the first element, use var i = 0;
Since these indexes start at 0, for an Array of 3 elements, the last index is 2. So you only want to run your loop while i is less than the array length: i < birthdays.length
You were skipping elements by doing i = i + 2. There seems to be no reason for it?
Something else worth mentionning: in JS, indentation does not matter - well, it does, but only to avoid making your eyes bleed. In fact, most websites use minified versions of their code, which fits on a single (often very long and ugly) line (example).
Here is your code, with only two lines fixed:
function find(birthdays) {
var uniqueBirthdays = [];
for (var i = 0; i < birthdays.length; i = i + 1) { // <-----
var count = 0;
for (var j = 0; j < birthdays.length; j = j + 1) { // <-----
if (birthdays[i] == birthdays[j]) {
count++;
}
}
if (count == 1) {
var n = uniqueBirthdays.length;
uniqueBirthdays[n] = birthdays[i];
}
}
return uniqueBirthdays;
}
// I used letters instead of birthdays for easier demo checking
var birthdays = ['a', 'b', 'a', 'c'];
console.log( find(birthdays) ); // ["b", "c"]
JS have direct methods tor that use Array.indexOf(), Array.lastIndexOf() and Array.filter()
uniques elements have same first position and last position
sample code:
const initailArray = [...'ldfkjlqklnmbnmykdshgmkudqjshmjfhmsdjhmjh']
const uniqueLetters = initailArray.filter((c,i,a)=>a.indexOf(c)===a.lastIndexOf(c)).sort()
console.log(JSON.stringify(uniqueLetters))

Eliminate duplicate values javascript

I try to draw a graph from tens of thousands points, but because this number is so big i need to reduce it. Many of them have duplicates. I tried to reduce the number using this:
var array=_.reject(data,function(object,i){
return i>0 && (data[i-1].a === object.a && data[i-1].b===object.b && data[i-1].c===object.c);
});
How can i modify this function, or to create a new one, in order to keep first and last value considered duplicate. Those are different by another attribute 'd' which represent a time stamp.
//return filtered points, compareFunction for sorting, equalFunction for
//removing points
function removeDuplicate(data,compareFunction,equalFunction) {
data.sort(function(pointa, pointb) {
var compare = compareFunction(pointa,pointb);
return compare;
});
var arr = new Array();
var prev = new Object();
var index = 0;
for (var i = 0; i < data.length; i++) {
if (i == 0 || !(equalFunction(prev,data[i]))) {
arr[index++] = data[i];
prev = data[i];
}
}
return arr;
}
function compareFunction(pointa,pointb){
return (pointa.a + pointa.b + pointa.c) - (pointb.a + pointb.b + pointb.c);
}
function equalFunction(pointa,pointb){
return pointa.a == pointb.a && pointa.b == pointb.b && pointa.c == pointb.c;
}
example - https://jsfiddle.net/8xu4Lwp2/
The simplest way to eliminate duplicates from an array in JavaScript is to cast it as a Set and then back to an Array. Sets don't store duplicates.
// not sure why setArr isn't logging, it does in Opera console.
arr=[1,1,2,2,3,3];
console.log(arr);
setArr=new Set(arr);
console.log(setArr);
newArr=[...setArr];
console.log(newArr);
Cool solution:
var unique = Array.from(new Set(arrayWithDuplicatedValue));

filter with object references lodash

I have an array, I need to chunk that array & manipulate parts of the chunks BUT I'd like to it to update my original array
I'm self taught with no computer science background so when it comes to technical inner workings I'm at a disadvantage.
var markers = ["one","two","three","four","five","six","seven","eight","nine"]
var chunks = _.chunk(markers, 5)
var result = _.chain(chunks[0]).last().value();
result = 'newValue'
console.log(chunks);
console.log(markers);
//was hopping to get
// ["one","two","three","four","newValue","six","seven","eight","nine"]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
I'm not quite sure I got your requirement right, but this changes the first and last element of each "chunk" (without really splitting the array).
var data = [
"one","two","three","four","five",
"one","two","three","four","five",
"one","two","three"
];
var chunkSize = 5,
numberOfChunks = Math.ceil(data.length / chunkSize),
indexOfFirstElementInChunk,
indexOfLastElementInChunk;
for (var i = 0; i < numberOfChunks; i++) {
indexOfFirstElementInChunk = (i * chunkSize);
data[indexOfFirstElementInChunk] = "first element";
indexOfLastElementInChunk = Math.min(data.length, ((i + 1) * chunkSize)) - 1;
if (indexOfFirstElementInChunk < indexOfLastElementInChunk) {
data[indexOfLastElementInChunk] = "last element";
}
}
console.log(data);

Javascript convert array of numbers with duplicates into unique sets of numbers

I have a javascript sorting algorithm problem which I am struggling to solve efficiently .
I have an array of numbers which I am calling cards e.g. [1,2,3,4,5,6,7,8,9,10]
Each day I have 6 teaching sets. In each set I want to display a maximum of 5 RANDOM & UNIQUE cards. Each card must be displayed exactly 3 times a day.
What I have done so far is to create 6 empty arrays (sets). I then iterate through my cards 3 times each attempting to add them to a random set if the card does not already exist in that array. Sometimes it works, but most of the time I get a problem where I have only one array with space left and that array already contains the card. my code:
Assume in my code that numberOfSetsPerCard = 3 & totalSets = 6. The only library available is JQuery.
shuffleIntoSets : function(cards, numberOfSetsPerCard, totalSets) {
var sets = [];
// initialize the sets as empty arrays
for (i = 0; i < totalSets; i++) {
sets[i] = [];
}
$.each(cards, function(index, card) {
for(x=0;x<numberOfSetsPerCard;) {
// attempt to place the card in a set which doesnt already contain the card
setNo = Math.floor((Math.random() * totalSets));
console.log("setNo: " + setNo);
if(jQuery.inArray(card,sets[setNo]) == -1 && sets[setNo].length<5) {
console.log(setNo + "does not contain: " + card);
sets[setNo].push(card);
console.log("Added the card, set now looks like :" + sets[setNo]);
x++;
}
}
});
return sets;
},
This is my solution to your problem, it is a bit long, but i think it a bit long, but it definitely creates randomness in the teach sets, and satisfy the conditions you have stated
codepen link: http://codepen.io/anon/pen/yyoaZy
html/include jquery:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
js:
//-----------------------------------------------
//For this question on StackOverflow:
//http://stackoverflow.com/questions/28192127/javascript-convert-array-of-numbers-with-duplicates-into-unique-sets-of-numbers
//-----------------------------------------------
var cards = [1,2,3,4,5,6,7,8,9,10];
var numOfTeachingSets = 6;
var numOfUniqueCardsPerTeachingSet = 5;
var numOfCardRepetitionPerDay = 3;
var shuffleCards = function(cards, numOfTeachingSets, numOfUniqueCardsPerTeachingSet, numOfRepetitionPerCard){
if(cards.length*numOfRepetitionPerCard != numOfTeachingSets*numOfUniqueCardsPerTeachingSet){
alert("invalid param");
return null;
}
//since each card is required to repeat numOfRepetitionPerCard times
//the available choices should be numOfRepetitionPerCard times of the original deck of cards
var availableCardChoices = cards.concat([]);
for (var i=0;i<numOfRepetitionPerCard-1;i++){
availableCardChoices = availableCardChoices.concat(cards);
}
//Record down items from [availableCardChoices] has been picked
var choosenList = [];
//Put 6 sets of unique cards into the result
var result = [];
for (var i=0;i<numOfTeachingSets;i++){
result.push( pickOutUniqueNumberSet(availableCardChoices,numOfUniqueCardsPerTeachingSet, choosenList) );
}
//return the result - an array of [numOfTeachingSets] arrays
return result;
}
//-----------------------------------------------------------
// Function:
// picks [cardsPerSet] number of unique item out of [availableChoices]
// each time an item is picked, this item is removed from [availableChoices]
//
// Important note: The number of card repetition is not really meaningful
// because if each round of picking produces unique sets,
// then the number of card repetition condition will be
// automatically satisfied.
//-----------------------------------------------------------
var pickOutUniqueNumberSet = function(availableChoices, cardsPerSet, disabledChoices){
if (cardsPerSet==0 || availableChoices.length==0){
return null;
}
var choosenSet = [];
var maxAttempts = 10000; //these 2 counter are used to prevent infinite looping
var attempts = 0;
for(var i=0;i<cardsPerSet;i++){
//items are choosen from [availableChoices] by their array index.
var randomIndex = Math.floor((Math.random() * availableChoices.length));
//repeatedly grab a random index from availableChoices till a unique one is selected
//unique item is an item that is not repeated in choosenSet, and its index is not in disabledChoices
while( (InArray(choosenSet, availableChoices[randomIndex]) || InArray(disabledChoices, randomIndex)) && attempts<maxAttempts){
randomIndex = Math.floor((Math.random() * availableChoices.length));
attempts++;
}
//Add this item to the chooseSet
choosenSet.push(availableChoices[randomIndex]);
//Add this item's index to disabledChoices
disabledChoices.push(randomIndex);
}
return choosenSet;
}
var InArray = function(array, itemToFind){
for(var i=0;i<array.length; i++){
if(array[i]==itemToFind){
return true;
}
}
return false;
}
//---------- Test --------
var teachingSets = shuffleCards(cards, numOfTeachingSets, numOfUniqueCardsPerTeachingSet, numOfCardRepetitionPerDay);
for(var i=0;i<teachingSets.length; i++){
document.write(teachingSets[i] + "<br>");
}

How to test if an id is present in an associative array

I'm am starting in javascript. I'm trying to do a little program that make a statistic upon the number of answer found in a text document.
The situation is this: each question has one id, e.g 8000001 and W if answer is good or R if answer is not good, e.g for an user answer is 8000001W. I have many user so many question of the same id. I want to get number of good answers per questions. E.g id: 800001 have W: 24 and "R": 5.
I have split the answer into id for 8000001 and ans for W or R. I wanted to create an associative table to get question[id]=["W": 0, "R": 0]. But I'm blocking on this. I've tried this code:
var tab = [];
tab[0] = [];
tab[0] = ['8000001W', '8000002W', '8000003W', '8000004R', '8000005W', '8000006R'];
tab[1] = [];
tab[1] = ['8000001R', '8000002W', '8000003R', '8000004W', '8000005R', '8000006W'];
var question = [];
var id;
for (var i=0;i<tab.length;i++) {
document.write("<dl><dt>tableau n° "+i+"<\/dt>");
for (var propriete in tab[i]) {
id = tab[i][propriete].slice(0,7);
var ans = tab[i][propriete].slice(7,8);
question[id] = [];
if(question[id]){
incrementResp.call(rep, ans);
}else{
var rep = initResp(ans);
question[id] = rep;
}
}
document.write("<\/dl>");
}
function incrementResp(type){
this.this++;
}
function initResp(t){
rep = [];
rep.W = (t=='W'?1:0);
rep.R = (t=='R'?1:0);
}
Based on what your want finally, the 'question' should be used as an object literal, defined as question = {} (similar to association array), what you defined here is an array literal. You can check this for more information about different types of literals in JavaScript:
https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Literals
In terms of your code, you can simple do like this:
if (question[id]) {
question[id][ans] += 1;
}
else {
var rep = initResp(ans);
question[id] = rep;
}
Also your 'initResp' function better to return an object literal 'rep', not as an array literal:
function initResp(t){
var rep = {};
rep.W = (t=='W'?1:0);
rep.R = (t=='R'?1:0);
return rep;
}
For an "associative array" in JavaScript, use a regular object. In the code below, "results" is one of these objects. It has two keys, "W" and "R" that point to numbers starting at 0. Just iterate through your answer arrays and continuously increment the correct key.
There are two ways to access a key in an object: 1) using brackets, 2) using "dot" notation. In the loop I use brackets because 'key' is a variable--it will resolve to "W" or "R" and therefore access the "W" or "R" key in that object. In the final two lines I use dot notation because "W" and "R" are literally the keys I want to access. It would also work if I did this instead: results['W']++ and results['R']++.
var tab = [];
tab[0] = ['8000001W', '8000002W', '8000003W', '8000004R', '8000005W', '8000006R'];
tab[1] = ['8000001R', '8000002W', '8000003R', '8000004W', '8000005R', '8000006W'];
var results = {
W: 0,
R: 0
};
// go through each tab
for (var tabIdx = 0; tabIdx < tab.length; tabIdx++) {
// go through each answer and apppend to an object that keeps the results
for (var i = 0; i < tab[tabIdx].length; i++) {
var answer = tab[tabIdx][i];
// the last character in the string is the "key", (W or R)
var key = answer.slice(-1);
// append to the results object
results[key]++;
}
}
console.log(results);
console.log(results.W); // 7
console.log(results.R); // 5
Open up your development console (on Chrome it's F12) to see the output.
This is how i resolved my problem for associative array.
var tab = [];
tab[0] = ['8000001W', '8000002W', '8000003W', '8000004R', '8000005W', '8000006R'];
tab[1] = ['8000001R', '8000002W', '8000003R', '8000004W', '8000005R', '8000006W'];
tab[2] = ['8000001R', '8000002W', '8000003R', '8000004W', '8000005R', '8000006W'];
var question = {};
for (var tabIndex = 0; tabIndex < tab.length; tabIndex++) {
for (var i = 0; i < tab[tabIndex].length; i++) {
var answer = tab[tabIndex][i];
var id = answer.slice(0,7);
var ans = answer.slice(-1);
if (question[id]) {
question[id][ans] += 1;
}else {
var results = initResp(ans);
question[id] = results;
}
}
}
console.log(question);
function initResp(t) {
var results = [];
results.W = (t === 'W' ? 1 : 0);
results.R = (t === 'R' ? 1 : 0);
//console.log(results);
return results;
}

Categories

Resources