Error in JS duplicate array entry method - javascript

I am trying to add user inputs into an array and throw an error alert if the user enters a duplicate value. The method below works fine for duplicates, but it also throws errors for non duplicate values. I am unable to understand why. Its probably something very simple, but I'm not seeing it.
addDIN(val) {
var arr = this.din_require_list;
if (arr.length == 0) {
arr.push(val)
}
else if (arr.length > 0) {
for (var i= 0; i < arr.length; i++) {
if (val != arr[i]) {
arr.push(val);
}
else if(val == arr[i]){
alert("duplicate entry");
arr.splice(i+1,1);
}
};
};
}
,

make it simpler
function insertUnique(val){
var arr = [];
if(!arr.includes(val)){
arr.push(val)
}else{
alert("Duplicate entry");
}
}
Array.include checks whether the value exists or not in given array.
refer this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

You are pushing into the array but not exiting the loop, so the loop keeps on running and matches the value and throws the error,
What you should be doing is run the for loop separately and keep a flag if it has a duplicate or not, and if no dupes are found add the element to the array
like
for (var i= 0; i < arr.length; i++) {
if(arr[i]== val){
dupeFound==1;
console.log("duplicate")
break;
}
}
if(dupeFound!=1) array.push(val)

at risk of being simplistic
why not?
var arr = [1,2,'c','dude what'];
var lookfor = 'dude';
if(arr.indexOf(lookfor) != -1){
console.log('dude string already exists on the array')
}
Therefore
var arr = [1,2,'c','dude what'];
var add = 1;
if((arr.indexOf(add) == -1)?arr.push(add): false){
console.log('added ',add);
}else{
console.log(add,'already in array');
}
console.log(arr);

Related

indexOf Array returning -1 even when the value is present in the array

I have a placeCollection collection which has an array called locFrnd.
As I was not able to use indexOf function on the locFrnd array of object I moved it to a new array called dup. As the main purpose of the dup was that i could use the data and get the indexOf function performed on it. $scope.Friend is the incoming data source and is also an array . user can send multiple values in $scope.Friend. The main logic that I want to check here is that if 2 values are there as user input in $scope.Friend both the values need to be checked one by one in locFrnd array.If they are not present than they need to be pushed in locFrnd array. The only challenge is that indexOf operation is referring to the last value of dup. e.g dup has r,j and $scope.Friend has r,j j from dup is compared to r from $scope.Friend and the next value is also not getting checked. I am not sure why this anonymous behavior is occurring in case of indexOf function
//if country exist
else if (cnt_exist == 1) {
alert("country exist");
var len = $scope.placeCollection[cnt_i].locFrnd.length;
for (var j = 0; j < len; j++) {
var dup = [];
dup[j] = $scope.placeCollection[cnt_i].locFrnd[j].name;
}
//check for friend now
alert("checking for friend");
//some code has to inserted here to handle Friends as it is an array
alert($scope.Friend.length);
for (var k = 0; k < $scope.Friend.length; k++) {
var frnd_exist = 0;
alert($scope.Friend[k]);
alert(dup.indexOf($scope.Friend[k]));
if (dup.indexOf($scope.Friend[k]) != -1) // friend exist
{
alert("entered friend comparison");
frnd_exist = 1;
}
if (frnd_exist == 1) // if friend does not exist
{
alert("friend exist");
} else if (frnd_exist == 0) {
var eachFriend = {
name: $scope.Friend[k]
}
$scope.placeCollection[cnt_i].locFrnd.push(eachFriend);
}
}
Answer is simple.
you are initializing dup in every iteration of the for loop. Initialize outside the loop
var dup = [];
for (var j = 0; j < len; j++) {
dup[j] = $scope.placeCollection[cnt_i].locFrnd[j].name;
}

Why is my duplicate removal script not capturing unique values

I'm trying to removal duplicates from a sorted list.
I wrote this script.
for(var i = 0; i < duplicateAuthors.length - 1; i++){
if(duplicateAuthors[i] == duplicateAuthors[i + 1]) { continue; }
else{
uniqAuthors.push(duplicateAuthors[i]);
}
}
It works except it does not capture unique values in the list. What am I doing wrong?
var uniqAuthors = [];
for(var i = 0; i < duplicateAuthors.length; i++){
if(uniqAuthors.indexOf(duplicateAuthors[i]) == -1) {
uniqAuthors.push(duplicateAuthors[i]);
}
}
The above code checks whether an object exist in an array or not, if not add it to array. Hence, at the end we will have an array of unique values.
Since object keys have to be unique I realized that you could also do the following to isolate unique values.
var uniqs = {};
for(var i = 0; i < duplicateAuthors.length ; i++){
uniqs[duplicateAuthors[i]] = null;
}
var uniqAuthors = Object.keys(uniqs);
This will take advantage of the fact that it's already sorted.
var previous;
var current;
for(var i = 0; i < duplicateAuthors.length; i++){
current = duplicateAuthors[i];
if (current && current != previous) {
uniqAuthors.push(current);
previous = current;
}
}

Get minimum and maximum of object property names that are integers

UPDATED (formulated the problem wrong, see note below)
I have an object that has a set of properties that are named with numbers as shown in the example. The 'numbered names' are not necessarily consecutive, nor do I know where they start or end. I do know that other properties will not be named with numbers.
I know that myObject["propName"] is the same as myObject.propName, but I deliberately write it in the first way because myObject.0 looks weird and doesn't get recognized by all editors.
How do I get the min- and maximum array index?
So in a situation like this
myObject["0"] = undefined
myObject["1"] = {}
myObject["2"] = undefined
myObject["3"] = {}
myObject["4"] = {}
myObject["5"] = undefined
myObject["someOtherProperty"] = {}
would give me this
minIndex(myObject) == 1
maxIndex(myObject) == 4
To all the answers before this edit
Thanks for your replies. I shouldn't have posted this question in a hurry and should have re-read it before committing. It was late and I was in a hurry. My apologies.
By actually seeing my wrong statement (using an array instead of an object) I think that, based on answers for my reformulated problem, I might need to rewrite my code to use an array instead of an object. The reason I'm using an object rather then an array is material for another question.
Efforts so far
I have tried finding a way of converting the property names to an array and then looping through them, but that has proven cludgy. I'm kind of looking for a less error-prone and elegant way.
Edit: Aha! Now the problem becomes more interesting.
Solution 1: Let's solve this in one shot, shall we? For max:
function maxIndex(obj){
var max = -1;
for(var i in myObject){
var val = parseInt(i);
if(isFinite(val)){
if(typeof obj[val] !== 'undefined' && val > max){
max = val;
}
}
}
return max;
}
I think you can convert this to min on your own ;)
Solution 2: Here I'll your object back into what we originally thought it was, in case you really loved one of the other solutions. Then the rest of the answer applies.
function convertObject(obj){
var output = [];
for(var i in myObject){
var val = parseInt(i);
if(isFinite(val)){
output[val] = obj[i]; //Gotta love JS
}
}
return output;
}
Continue as planned!
To find the smallest, begin at the bottom and work your way up until you find it.
function minIndex(myArray){
for(var i = 0; i < myArray.length; i++){
if(typeof myArray[i] !== 'undefined')
return i;
}
}
To get the biggest, start at the top.
function maxIndex(myArray){
for(var i = myArray.length - 1; i >= 0; i--){
if(typeof myArray[i] !== 'undefined')
return i;
}
}
Both are worst case O(n). You can't really do better because the whole array could be empty, and you'd have to check every element to be positive.
Edit: As is mentioned, you can also check if something is not undefined by simply writing if(myArray[i]). Whatever suits your fancy.
var myObject = {};
myObject["0"] = undefined;
myObject["1"] = {};
myObject["2"] = undefined;
myObject["3"] = {};
myObject["4"] = {};
myObject["5"] = undefined;
myObject["someOtherProperty"] = {};
var keys = Object.keys(myObject).map(Number).filter(function(a){
return isFinite(a) && myObject[a];
});
var min = Math.min.apply(Math, keys);
var max = Math.max.apply(Math, keys);
console.log(min, max); //Logs 1 and 4
Documentation and compatibility information for all:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter
Try looping through the array until you find the 1st non-undefined element.
function minIndex(arr){
for(var i = 0, len = arr.length; i < len; i++){
if(arr[i] !== undefined){
return i;
}
}
}
For max index, do the same thing, except in reverse.
function maxIndex(arr){
for(var i = arr.length-1, len = 0; i >= len; i--){
if(arr[i] !== undefined){
return i;
}
}
}
Min:
for(var i = 0; i < myArray.length; i++) {
if(myArray[i] != undefined) {
return i;
}
}
Max:
for(var i = myArray.length-1; i >= 0; i--) {
if(myArray[i] != undefined) {
return i;
}
}
try something like this:
function minIndex(var array){
for(var i = 0; i < array.length; i++)
{
if(typeof array[i] != "undefined")
return i;
}
return null;
}
function maxIndex(var array){
var returnIndex = -1;
for(var i = 0; i < array.length; i++)
{
if(typeof array[i] != "undefined")
returnIndex = i;
}
if(returnIndex !== -1) return returnIndex;
else return null;
}
this takes advantage of the fact that for..in only iterates over defined elements, and uses the index:
function minIndex(arr){ for(el in arr){return el} }
function maxIndex(arr){var v; for(el in arr){v = el}; return v }
CAVEATS:
The second function is not very efficient though, since it loops through the entire array.
This wont work if you are EXPLICITLY setting the undefined indexes.
var max=0;
var min=myArray.length;
for (var i in myArray)
if (myArray[i]!==undefined)
{
max=Math.max(i, max);
min=Math.min(i, min);
}

Looping through arrays to check for patterns

I'm trying to loop through an array to check for a specific pattern but keep getting no output afterwards. Not sure what I've done wrong! I would appreciate any help!
I am testing for the pattern at or hat.
sample = ["cat fat hat mat", "that the who"]
searchTerm = prompt("Testing?");
function count(sample, searchTerm)
{
for (i=0;i<sample.length;i++)
{
if (sample[i].indexOf(searchTerm) == -1)
{
return 0;
}
return count(sample.substring(sample.indexOf(searchTerm) + searchTerm.length), searchTerm) + 1;
}
}
alert(count(sample, searchTerm));
Rehashed code
search = ["cat fat hat mat", "that the who"];
var pattern = prompt('Search?');
function count(sample, searchTerm)
{
var count, i;
count = 0;
for (i=0; i < sample.length; i++)
{
if (sample[i].indexOf(searchTerm) !== -1)
{
count++;
}
}
return count;
}
count(search, pattern);
I've redone everything and it still gives no output.
There are a couple of problems with this code. The most immediate one is you are calling substring on an array and not a string.
return count(sample.substring ...
Likely you meant to say
return count(sample[i].substring ...
The second issue though is that you need to divide the logic up a bit. You need to divide it up into sections that count the occurrences in a word and that which iterates through the array. Today they are intertwined and results in odd behavior because you end up passing non-arrays to places expecting arrays
function count(sample, searchTerm) {
var num = 0;
for (i=0;i<sample.length;i++) {
var current = sample[i];
var index = current.indexOf(searchTerm);
while (index >= 0) {
num++;
index = current.indexOf(searchTerm, index + 1);
}
}
return num;
}
Working Fiddle: http://jsfiddle.net/wrNbL/
You don't need to use recursion here, just iterate through the array once counting if the search term matches.
function count(sample, searchTerm)
{
var count, i;
count = 0;
for (i=0; i < sample.length; i++)
{
if (sample[i].indexOf(searchTerm) !== -1)
{
count++;
}
}
return count;
}

How can I search for a value in an array and delete just one of those values if 2 or more is found?

I have an array
var aos = ["a","a","a","b","b","c","d","d"];
I want to know if I can remove just 1 item if it finds 2 or more of the same value in the array. So for instance if it finds
"a", "a"
it will remove one of those "a"
This is my current code:
var intDennis = 1;
for (var i = 0; i < aos.length; i++) {
while (aos[i] == aos[intDennis]) {
aos.splice(i, 1);
intDennis++;
console.log(aos[intDennis], aos[i]);
}
intDennis = 1;
}
NOTE: My array is sorted.
Edited after better understanding of OP use-case.
Updated solution and fiddle test to incorporate suggestion from pst in comments.
(Not for nothing, but this method does not require the original array be sorted.)
Try this...
var elements = [];
var temp = {};
for (i=0; i<aos.length; i++) {
temp[aos[i]] = (temp[aos[i]] || 0) + 1;
}
for (var x in temp) {
elements.push(x);
for (i=0; i<temp[x]-2; i++) {
elements.push(x);
}
}
Fiddle Test
Because you said you have a sorted array, you only need to remove the second time a element is found. You only need one for.
The splice() function returns the removed element so, just use it to not remove more elements of that kind.
This solution is more clean and efficient.
var aos = ["a","a","a","b","b","c","d","d"];
var lastRemoved = "";
for (var i = 1; i < aos.length; i++) {
if (aos[(i-1)] == aos[i] && lastRemoved != aos[i]) {
lastRemoved = aos.splice(i, 1);
}
}
Code tested and working. Result: ["a", "a", "b", "c", "d"]
I don't believe there's any better way to do this on an unsorted array than an approach with O(n^2) behaviour. Given ES5 array-builtins (supported in all modern browsers, though not in IE prior to IE9), the following works:
aos.filter(function(value, index, obj) { return obj.indexOf(value) === index; })
UPDATED ANSWER TO REMOVE ONLY 1 DUPLICATE:
Assuming that each object will resolve to a unique String, here's a potential solution. The first time the object is detected, it sets a counter for that object to one. If it finds that object again, it splices that element out and increments the associated counter. If it finds that element more times, it will leave it alone.
var elements = {};
for (var i = 0; i < aos.length; i++) {
if(elements[aos[i]]){
if(elements[aos[i]] == 1){
aos.splice(i,1);//splice the element out of the array
i--;//Decrement the counter to account for the reduced array
elements[aos[i]]++;//Increment the count for the object
}
} else {
elements[aos[i]] = 1;//Initialize the count for this object to 1;
}
}
Here's the test fiddle for this.
I would not mutate the input -- that is, don't use splice. This will simplify the problem a good deal. Using a new array object here may actually be more efficient. This approach utilizes the fact that the input array is sorted.
Consider: (jsfiddle demo)
var input = ["a","a","a","b","b","c","d","d"]
var result = []
for (var i = 0; i < input.length; i++) {
var elm = input[i]
if (input[i+1] === elm) {
// skip first element (we know next is dup.)
var j = i + 1
for (; input[j] === elm && j < input.length; j++) {
result.push(input[j])
}
i = j - 1
} else {
result.push(elm)
}
}
alert(result) // a,a,b,c,d
Happy coding.
Replace === with a custom equality, as desired. Note that it is the first item is omitted from the output, which may not always be "correct".
REVISED EXAMPLE
function removeDuplicate(arr) {
var i = 1;
while(i < arr.length) {
if(arr[i] == arr[i - 1]) {
arr.splice(i, 1);
}
while(arr[i] == arr[i - 1] && i < arr.length) {
i += 1;
}
i += 1;
}
return arr;
}
alert(removeDuplicate(["a","a","a","b","b","c","d","d"]));

Categories