javascript get the last duplicate value index javascript - javascript

I have an array to be like this var arr = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5].
so it contains duplicate values. In here last index value of
'0' is '3',
'1' is '4',
'2' is '5',
'3' is '13', and so on.
And i counted total duplicate values
var counts = {};
arr.forEach(function(x) { counts[x] = (counts[x] || 0)+1; })
but i want to know last duplicate value index only. please help me.
thanks in advance

var arr = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5];
var existingItems = {};
arr.forEach(function(value, index) {
existingItems[value] = index;
});
console.log(existingItems);

Simple loop and check to see if next index is different
var arr = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5]
var indexes = arr.reduce(function(result, cur, ind, arr){
if (ind+1===arr.length || cur != arr[ind+1]) { //check to see if last or different
result.push(ind); //if different, store the index
}
return result;
},[]);
console.log(indexes);

Array.prototype.lastIndexOf() comes in handy here:
var arr = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5];
var out = {};
arr.forEach(function(item) {
if(!out.hasOwnProperty(item)) {
out[item] = arr.lastIndexOf(item);
}
});
console.log(out); // Object {0: 3, 1: 4, 2: 5, 3: 13, 4: 15, 5: 22}
This will also work for unsorted input arrays.

Well, what you can do is check if a value is a duplicate (count > 1) and then use the second parameter of forEach which is the index to remember it. Something like:
var arr = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5];
var counts = {};
var indexes = {};
arr.forEach(function(x, idx) {
counts[x] = (counts[x] || 0) + 1;
if(counts[x] > 1) { indexes[x] = idx; } // check if a value is a duplicate and update its index
});
// logs the last index of all duplicate values
console.log(indexes); // {0: 3, 3: 13, 4: 15, 5: 22}
If you want the last index of all values, not just duplicates, you can omit the count > 1 check:
var arr = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5];
var counts = {};
var indexes = {};
arr.forEach(function(x, idx) {
counts[x] = (counts[x] || 0) + 1;
indexes[x] = idx; // update value index
});
// logs the last index of all values
console.log(indexes); // {0: 3, 1: 4, 2: 5, 3: 13, 4: 15, 5: 22}

Related

Spot start and end index of values outside specified bounds?

I have 3 arrays of size n :
let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];
let n = values.length;
I am trying to spot the indexes of the start and end of the "zones" where min_arr[i] > values[i] or max_arr[i] < values[i].
In the previous arrays the first zone : values[4] = 7 > 6 = max_arr[4] and !(values[5] = 6 > 6 = max_arr[5]) thus start = 4 and end = 5.
In the previous arrays the second zone : values[8] = 3 < 4 = min_arr[8] and values[9] = 3 < 4 = min_arr[9] but !(values[10] = 4 < 3 = min_arr[10]) thus start = 8 and end = 10.
In the previous arrays the expected output would be : [[4, 5], [8, 10]].
Nb: It does not matter if the last end index is greater than n.
Here is my code so far :
let temp = values
.map((e, i) => min_arr[i] > e || max_arr[i] < e ? i : undefined)
.filter((e) => e);
console.log(temp);
Output
[4, 8, 9]
My logic here is to first get all the indexes where the value is not in the bounds before removing consecutive values and adding the end value.
let res = [];
let start = temp[0];
for (let i = 0; i < temp.length; i++) {
if (i + 1 == temp.length) {
res.push([start, temp[i] + 1]);
break;
}
if (temp[i] + 1 != temp[i + 1]) {
res.push([start, temp[i] + 1]);
start = temp[i + 1];
}
}
console.log(res);
Output
[[4, 5], [8, 10]]
As a beginner in JavaScript, I find this method crude and I believe that the whole process can be done in a declarative way. How should I proceed ?
Please don't hesitate to edit this question if it lacks clarity.
Here are not so crude methods, probably they are in declarative way, also with handling some corner-cases. Corner cases i mean in result you are expencting arrays with 2 elements, open index and close index. So if the last element in array is out of bound - still an array with 2 elements will be returned. And at this point im curious about the correct output, probably you have to clarify it a bit. I assumed that indexes shoult be "first index of item that is out of bounds" and "last index of item that is out of bounds", not the "last index + 1"
let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];
function getZones(values, predicateFn) {
const reduced = values.reduce(
(acc, curr, i) => {
const isMet = predicateFn(curr, i);
if (isMet) {
if (acc._zone) acc._zone[1] = i;
else acc._zone = [i];
} else if (acc._zone) {
// -1 due to current index is ok, previous was not.
acc._zone[1] = i - 1;
acc.result.push(acc._zone);
acc._zone = undefined;
}
return acc;
},
{
_zone: undefined,
result: []
}
);
// Case when zone was opened and not closed.
// Happens for last item only.
const { _zone, result } = reduced;
if (_zone) {
if (_zone.length === 1) {
_zone[1] = _zone[0];
}
result.push(_zone);
}
return result;
}
const res = getZones(values, (curr, i) => curr < min_arr[i] || curr > max_arr[i]);
console.log(JSON.stringify(res));
Test set i checked with:
const testSets = [
{
// Original set
values: [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5],
min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3],
max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7]
// [[4,4],[8,9]]
},
{
// with starting and ending outs
values: [2, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 10],
min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3],
max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7]
// [[0,0],[4,4],[8,9],[12,12]]
},
{
// with starting and ending "wave"
values: [2, 8, 2, 6, 7, 6, 5, 4, 3, 3, 4, 2, 2, 10],
min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3],
max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7]
// [[0,2],[4,4],[8,9],[11,13]]
},
{
// Completely out of bounds
values: [2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8, 8],
min_arr: [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3],
max_arr: [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7]
// [[0,13]]
}
];
Also, here is a codesandbox so you can check the correct output and behavior.
Your method will work only for 2 consecutive values , try an example with more consecutive values like [[2, 7], [8, 11]] and check your method .
The solution can be the next:
let values = [5, 5, 5, 6, 7, 6, 5, 4, 3, 3, 4, 5, 5];
let min_arr = [3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3];
let max_arr = [7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7];
const result = values
.map((num, i) => (min_arr[i] > num || max_arr[i] < num ? i : undefined))
.reduce((previousValue, currentValue, currentIndex, array) => {
if ((currentValue || currentValue === 0) && !array[currentIndex - 1]) {
const findNextSibling = array.slice(currentIndex).findIndex(i => !i);
const finalConsecutiveValue =
findNextSibling === -1 || findNextSibling === 0
? 1
: findNextSibling + currentIndex;
previousValue.push([currentValue, finalConsecutiveValue]);
}
return previousValue;
}, []);
console.log('result', result);

JavaScript: Change all repeated values to 0 in array

I have an array with duplicate values
let ary = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
I want to set the repeated values to 0:
[0, 0, 0, 0, 7, 8, 0, 0, 2, 0, 6, 4, 0]
can find out the repeated value, but I want to change the repeated value to 0, is there any better way?
let ary = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
Array.prototype.duplicate = function () {
let tmp = [];
this.concat().sort().sort(function (a, b) {
if (a == b && tmp.indexOf(a) === -1) tmp.push(a);
});
return tmp;
}
console.log(ary.duplicate()); // [ 1, 3, 5, 9 ]
// ? ary = [0, 0, 0, 0, 7, 8, 0, 0, 2, 0, 6, 4, 0];
You could use indexOf() and lastIndexOf() method to solve your problem.
const array = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
const ret = array.map((x) =>
array.indexOf(x) !== array.lastIndexOf(x) ? 0 : x
);
console.log(ret);
const ary = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
// get set of duplicates
let duplicates = ary.filter((elem, index, arr) => arr.indexOf(elem) !== index)
duplicates = new Set(duplicates);
// set duplicate elements to 0
const res = ary.map(e => duplicates.has(e) ? 0 : e);
console.log(...res);
First, count values and store them in an object. Then loop over the array and check from that stored object whether the count of specific value is greater than 1 or not, if greater than 1, set that to 0. Here is the working example:
let ary = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
let countValue = {}, len = ary.length;
for (i = 0; i < len; i++) {
if (countValue[ary[i]]) {
countValue[ary[i]] += 1;
} else {
countValue[ary[i]] = 1;
}
}
for (i = 0; i < len; i++) {
if (countValue[ary[i]] > 1) {
ary[i] = 0;
}
}
console.log(...ary);
Probably this is the quickest algorithm, though it will alter your original array.
const array = [5, 1, 3, 5, 7, 8, 9, 9, 2, 1, 6, 4, 3];
const map = {};
for (let ind = 0; ind < array.length; ind++) {
const e = array[ind];
if (map[e] === undefined) {
map[e] = ind;
} else {
array[map[e]] = 0;
array[ind] = 0;
}
}
console.log(...array);

Getting a "not defined" error in my JavaScript code when I think it is defined

I am working on a project for SkillCrush and am getting a "not defined" error, when I feel as though I've defined the variable at the top of the code. I 100% know I'm doing something wrong, but not sure what. Any suggestions?
var createPolitician = function (name)
{
var politician = {}; //is this not defined here?
politician.name = name;
politician.electionResults = null;
politician.totalVotes = 0;
return politician;
};
var oscar = createPolitician("Oscar Jiminez");
var luke = createPolitician("Luke Spencer");
oscar.electionResults = [5, 1, 7, 2, 33, 6, 4, 2, 1, 14, 8, 3, 1, 11, 11, 0, 5, 3, 3, 3, 7, 4, 8, 9, 3, 7, 2, 2, 4, 2, 8, 3, 15, 15, 2, 12, 0, 4, 13, 1, 3, 2, 8, 21, 3, 2, 11, 1, 3, 7, 2];
luke.electionResults = [4, 2, 4, 4, 22, 3, 3, 1, 2, 15, 8, 1, 3, 9, 0, 6, 1, 5, 5, 1, 3, 7, 8, 1, 3, 3, 1, 3, 2, 2, 6, 2, 14, 0, 1, 6, 7, 3, 7, 3, 6, 1, 3, 17, 3, 1, 2, 11, 2, 3, 1];
oscar.electionResults[9] = 1;
luke.electionResults[9] = 28;
oscar.electionResults[4] = 17;
luke.electionResults[4] = 38;
oscar.electionResults[43] = 11;
luke.electionResults[43] = 27;
console.log(oscar.electionResults);
console.log(luke.electionResults);
politician.countTotalVotes = function()
{
this.totalVotes = 0;
for (var i = 0; i < this.electionResults.length; i++);
{
this.totalVotes = this.totalVotes + this.electionResults[i];
}
}
oscar.countTotalVotes();
luke.countTotalVotes();
console.log(oscar.totalVotes);
console.log(luke.totalVotes);
Error:
"error"
"ReferenceError: politician is not defined
at reloyur.js:32:1"
politician.countTotalVotes = ...
That won't work as politician only exists while you create luke or oscar (it then points to one of them). Instead you could do:
luke.countTotalVotes = oscar.countTotalVotes = function() { /*...* };
But for more politicians that gets a bit complicated. You could however just make a function that you pass a politician into:
function countTotalVotes(politician) {
//...
}
countTotalVotes(luke);
Or you use the power of inheritance.
As I suggested in comments, you can rewrite Politician as a class, which basically gives you a template for reusable functionality. If you're not familiar with the concept, a good google term would be "prototypal inheritance" for follow-up on the subject in general. For now, here's a rewrite of your script using a class:
class Politician {
constructor (name) {
this.name = name;
this.electionResults = [];
}
// no need to even write a .countTotalVotes() method
// just define .totalVotes as a getter that does the work
get totalVotes () {
var total = 0;
for (var i = 0; i < this.electionResults.length; i++) {
total += this.electionResults[i];
}
return total;
}
}
var oscar = new Politician("Oscar Jiminez");
var luke = new Politician("Luke Spencer");
oscar.electionResults = [5, 1, 7, 2, 33, 6, 4, 2, 1, 14, 8, 3, 1, 11, 11, 0, 5, 3, 3, 3, 7, 4, 8, 9, 3, 7, 2, 2, 4, 2, 8, 3, 15, 15, 2, 12, 0, 4, 13, 1, 3, 2, 8, 21, 3, 2, 11, 1, 3, 7, 2];
luke.electionResults = [4, 2, 4, 4, 22, 3, 3, 1, 2, 15, 8, 1, 3, 9, 0, 6, 1, 5, 5, 1, 3, 7, 8, 1, 3, 3, 1, 3, 2, 2, 6, 2, 14, 0, 1, 6, 7, 3, 7, 3, 6, 1, 3, 17, 3, 1, 2, 11, 2, 3, 1];
oscar.electionResults[9] = 1;
luke.electionResults[9] = 28;
oscar.electionResults[4] = 17;
luke.electionResults[4] = 38;
oscar.electionResults[43] = 11;
luke.electionResults[43] = 27;
// console.log(oscar.electionResults);
// console.log(luke.electionResults);
// these are no longer required
// oscar.countTotalVotes();
// luke.countTotalVotes();
console.log(oscar.name, 'has', oscar.totalVotes, 'votes');
console.log(luke.name, 'has', luke.totalVotes, 'votes');
Move your countTotalVotes function into your create function:
var createPolitician = function (name)
{
var politician = {};
politician.name = name;
// set to an empty array so this is defined
politician.electionResults = [];
politician.totalVotes = 0;
// here politician exists, add a function to the object that you can call later
politician.countTotalVotes = function()
{
this.totalVotes = 0;
for (var i = 0; i < this.electionResults.length; i++)
{
this.totalVotes = this.totalVotes + this.electionResults[i];
}
}
return politician;
};
I corrected your mistakes in your code. You could change your code like follows:
function createPolitician(name)
{
var politician =
{
name: name,
electionResults: null,
totalVotes: 0,
countTotalVotes: function()
{
//this.totalVotes = 0; <- irrelevant because you use it only one time
for(var i = 0; i < this.electionResults.length; i++)//";" symbol on the end is your mistake too
{
this.totalVotes += this.electionResults[i];
}
}
};
return politician;
};
var oscar = createPolitician("Oscar Jiminez");
var luke = createPolitician("Luke Spencer");
oscar.electionResults = [5, 1, 7, 2, 33, 6, 4, 2, 1, 14, 8, 3, 1, 11, 11, 0, 5, 3, 3, 3, 7, 4, 8, 9, 3, 7, 2, 2, 4, 2, 8, 3, 15, 15, 2, 12, 0, 4, 13, 1, 3, 2, 8, 21, 3, 2, 11, 1, 3, 7, 2];
luke.electionResults = [4, 2, 4, 4, 22, 3, 3, 1, 2, 15, 8, 1, 3, 9, 0, 6, 1, 5, 5, 1, 3, 7, 8, 1, 3, 3, 1, 3, 2, 2, 6, 2, 14, 0, 1, 6, 7, 3, 7, 3, 6, 1, 3, 17, 3, 1, 2, 11, 2, 3, 1];
oscar.electionResults[9] = 1;
luke.electionResults[9] = 28;
oscar.electionResults[4] = 17;
luke.electionResults[4] = 38;
oscar.electionResults[43] = 11;
luke.electionResults[43] = 27;
console.log(oscar.electionResults);
console.log(luke.electionResults);
oscar.countTotalVotes();
luke.countTotalVotes();
console.log(oscar.name, 'has', oscar.totalVotes, 'votes');
console.log(luke.name, 'has', luke.totalVotes, 'votes');
The error message should be accompanied with a line and column number. In this case, the error is occurring on line 32:
politician.countTotalVotes = function()
In the definition of the createPolitician function, you declared a variable named politician. var creates a variable that lives within the function it was declared in. If it is not inside of a function, it creates a global variable.
You left the function the variable was declared in, and thus it isn't usable anymore.
If you think about it, it'd be very ambiguous if you could re-use that politician variable later on. What would it refer to?
If you want to be able to call countTotalVotes() on the politicians, then Patrick's comment about using a Class is a good approach to take. You could also assign the function to the politician object that you return from createPolitician - this would give each instance of the politician its own copy of the function.
It's all about variable scope. Declare the politician object variable outside of the createPolitician function for you to access out of the function. It cannot be accessed out of its scope that is why you get an undefined error.

Return ONLY one iteration of a pattern in an array in Javascript

I'm trying to find and return a pattern (made up of numbers) in an array, but only return the pattern once.
ex. findPattern([1, 2, 3, 4, 5]);
should return [1]; not [1,1,1,1];
ex2. findPattern([1, 5, 4, 8, 7, 11, 10, 14, 13]);
should return ([4, -1]); not [ 4, -1, 4, -1, 4, -1, 4, -1 ];
ex3. findPattern([1, 5, 2, 3, 1, 5, 2, 3, 1]);
should return [ 4, -3, 1, -2, ]; not [ 4, -3, 1, -2, 4, -3, 1, -2 ];
Any thoughts on how I could do this simply, with a function findPattern(arr){}?
It appears that you want to remove duplicates from an array. You can leverage the Set class to make a function like so:
const unique = xs => [ ...new Set(xs) ];
Then to use:
unique(findPattern([ 1, 2, 3, 4, 5 ])); // [ 1 ]
More information about Set is available on MDN.

How can I change the position of a particular item in an array?

I'm trying to change an item's index position in an array, but I cannot figure out a way.
{
"items": [
1,
3,
2
]
}
You can use splice to move an element in an array:
var arr = [
1,
3,
2
];
var oldIndex = 2,
newIndex = 1;
arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]);
This makes [1, 2, 3]
The internal splice removes and returns the element, while the external one inserts it back.
Just for fun I defined a generic function able to move a slice, not just an element, and doing the computation of the index:
Object.defineProperty(Array.prototype, "move", {
value:function(oldIndex, newIndex, nbElements){
this.splice.apply(
this, [newIndex-nbElements*(newIndex>oldIndex), 0].concat(this.splice(oldIndex, nbElements))
);
}
});
var arr = [0, 1, 2, 7, 8, 3, 4, 5, 6, 9];
arr.move(5, 3, 4);
console.log('1:', arr) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
var arr = [0, 1, 2, 7, 8, 3, 4, 5, 6, 9];
arr.move(3, 9, 2);
console.log('2:', arr); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
var arr = [0, 1, 2, 4, 5, 3, 6, 7];
arr.move(5, 3, 1);
console.log('3:', arr); // [0, 1, 2, 3, 4, 5, 6, 7]
var arr = [0, 3, 1, 2, 4, 5, 6, 7];
arr.move(1, 4, 1);
console.log('3:', arr); // [0, 1, 2, 3, 4, 5, 6, 7]
JS Bin
If you want to sort them in Unicode order (where numbers become strings) you can use sort() function.
items.sort();
If you have your custom order, you need to provide a sort function to the sort function.
function compare(a, b) {
if (a is less than b by some ordering criterion) {
return -1;
}
if (a is greater than b by the ordering criterion) {
return 1;
}
// a must be equal to b
return 0;
}
and you use it like this:
items.sort(compare(a, b));

Categories