3

I want to remove duplicates in my array with jQuery

The array

[[["Time",0],["Budget",1],["Scope",2],["Technical",3],["Budget",1]]]

If there is a name ("Budget") in this example which appears several times, then I want to remove this value pair.

I tried a lot but nothing worked so far. I tried to iterate trough the array and set a duplicate variable and just add the items with no duplicates to a new array

  var items       = new Array ();
// get the data with ajax request
 $.ajax({
                url : "localhost/..",
                dataType : 'json',
                success: function(data) {

for (var prop_name in data.items) {
                    var duplicate = 0;
                    var count = 0;

// count how often the value appears
for (i = 0; i < data.items.length; i++) {
                    if (data.items[prop_name] == data.items[i]){
                        var count = count+1               
                        }
                }
// if there are duplicates, just add the value once
for (i = 0; i < items.length; i++) {    
                if (data.items[prop_name] == data.items[i]){
                duplicate = duplicate+1;
                    }
                if (duplicate <= 1){
                        items.push([ data.items[prop_name], count]) 
                    }
                duplicate = 0;
            }
}
2
  • Are you sure the data.items is an array of an array of arrays? It seems like you have one pair of brackets too many. Can you provide the output of console.log(JSON.stringify(data.items)) to be sure about this? Commented Jul 2, 2016 at 8:54
  • yes sorry, at the end it is pushed in an array again. Because jqplot(to make charts) needs that data format Commented Jul 2, 2016 at 9:21

3 Answers 3

3

Take a look at the following example. You can not use indexOf or $.inArray directly.

$ar=[["Time",0],["Budget",1],["Scope",2],["Technical",3],["Budget",1]];
$finalAr = [];
for($i=0;$i<$ar.length;$i++){
	$currentPair = $ar[$i];
  $pos = null;
  for($j=0;$j<$finalAr.length;$j++){
  	if($finalAr[$j][0] == $currentPair[0] &&$finalAr[$j][1] == $currentPair[1]){
    	$pos = $j;
    }
  }
  if($pos == null){
  	$finalAr.push($currentPair);
  }
}
for($i=0;$i<$finalAr.length;$i++){
  $("#result").append($finalAr[$i][0]+"-->"+$finalAr[$i][1]+"<br/>");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>

Sign up to request clarification or add additional context in comments.

1 Comment

I know this is old, but brilliant!
3

jQuery is not necessary for this task. Also note that creating a new array is different than removing elements from an existing array.

Creating a new array:
A simple record of previously iterated 'keys' can prevent duplicates from being copied.

Using ES5's Array.prototype.filter makes this a trivial task:

var data = [["abc", 1], ["def", 2], ["ghi", 3], ["abc", 4], ["jkl", 5]];
var prev = {};

var filteredData = data.filter( function(arr) {

  var key = arr[0];

  if (prev[key])
    return false;

  return (prev[key] = true);
});

console.log(filteredData);
Note: There is always a time vs space trade off with algorithms. This hash lookup takes 1 unit of time vs a nested loop's n units of time (each element of the array), per array item. The hash storage takes up memory, while the loop doesn't.

For small data sets this is irrelevant, but for larger sets it's something to consider.

Removing elements:
Otherwise you'll have to remove* the duplicates as you discover them.

Array.prototype.splice can remove elements from an array.

*May hit some performance issues, but if data is being managed on the client side you have far bigger issues to deal with anyway.

Comments

1

The problem in your code is that you compare arrays like this:

 data.items[prop_name] == data.items[i]

Both sides of the equation represent arrays, and even though their content might be the same, they don't reference the same array. So the equation will fail for all elements, except when prop_name === i, resulting in a count of 1 for all elements.

To illustrate, this will output false:

console.log(["Budget",1] == ["Budget",1]);

Also, your array is more deeply nested than you account for in your algorithm, so you need to address data.items[0] in your main loop.

I would suggest to use array functions for what you try to achieve, and use a temporary object for registering the counts per string, so you don't have to loop within a loop.

You could use filter for that, and provide the thisArg argument so we can use the this object for keeping the count of encountered names:

var items = [data.items[0].filter(function (pair) {
    return (this[pair[0]] = (this[pair[0]] || 0) + 1) === 1;
}, {})];

var data = {};
data.items = [[["Time",0],["Budget",1],["Scope",2],["Technical",3],["Budget",1]]];

var items = [data.items[0].filter(function (pair) {
    return (this[pair[0]] = (this[pair[0]] || 0) + 1) === 1;
}, {})];

console.log('before: ', data.items);
console.log('after: ', items);

This code only compares the string part of the pairs. If it is possible to have an array like this:

[[["Time",0],["Time",1]]];

... then the above solution will eliminate the second pair. But if you want to keep both in case the numerical part is different, then you need to adapt the code further:

var items = [data.items[0].filter(function (pair) {
    return (this[pair[0]+pair[1]] = (this[pair[0]+pair[1]] || 0) + 1) === 1;
}, {})];

NB: you don't really need jQuery for this.

3 Comments

thx for your detailed explanation! console.log(["Budget",1] == ["Budget",1]) yes that returns false but then i dont understand why does that work for (i = 0; i < data.items.length; i++) { if (data.items[prop_name] == data.items[i]){ var count = count+1 } }
because it references the same array?
Indeed, it will work exactly one time for each element, and this is when the loop gets the value i that is equal to prop_name: in that case you are really comparing the same array. Note that at no point the comparison looks at the array contents. It's the array references that are compared. When both reference the same memory location, they are equal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.