2

I have a sorted array like this:

var a= [
    {id:"1", name:"A", address:"A"},
    {id:"2", name:"A", address:"B"},
    {id:"3", name:"A", address:"C"},
    {id:"4", name:"B", address:"A"},
    {id:"5", name:"B", address:"B"},
    {id:"6", name:"C", address:"A"},
    {id:"7", name:"C", address:"B"},
    {id:"8", name:"C", address:"C"},..

What I want to do is get the index of those duplicated 'names' like

index 0-2 => "A";
index 3-4 => "B";
index 5-7 => "C";

Or even counting those duplicates will do such as 3 for A, 2 for B, 3 for C.

        var counter = 0;
        var prev = "";
        var next = "";
        var prevLink = a[0].name;

        for (var i = 0; i < a.length; i++) { 

         if(i >= ssRow.length){
             //do nothing
        }else{        
          next  = a[i+1].name;  
        } 

        if(prev== next){
          counter++;
        }else{        
          counter = 0;
          prevLink = a[i].name;      
        }
          //play with counter variable
        }

But it's not working as expected. Is there a much better way or efficient way to do it?

2
  • @silentcoder14,it is working for you ? Commented May 23, 2017 at 10:55
  • did you checked my answer ? I hope it will work as per your expectation. Commented May 23, 2017 at 17:16

7 Answers 7

4
 let dupes = {};
 const array= [
        {id:"1", name:"A", address:"A"},
        {id:"2", name:"A", address:"B"},
        {id:"3", name:"A", address:"C"},
        {id:"4", name:"B", address:"A"},
        {id:"5", name:"B", address:"B"},
        {id:"6", name:"C", address:"A"},
        {id:"7", name:"C", address:"B"},
        {id:"8", name:"C", address:"C"}];
 array.forEach((item,index) => {
   dupes[item.name] = dupes[item.name] || [];
   dupes[item.name].push(index);
 });       
 for(let name in dupes) console.log(name+'->indexes->'+dupes[name]+'->count->'+dupes[name].length)
Sign up to request clarification or add additional context in comments.

6 Comments

array.forEach((item,index) => { dupes[item.name] = dupes[item.name] || []; dupes[item.name].push(index); }); can this be done in a normal for loop?
@silent_coder14, yes, you should use a for statement
thanx.. also, what this line means: dupes[item.name] = dupes[item.name] || [];
This line mean following: if dupes[item.name] is undefined then initialize it with new array, and if not remains same.
@silent_coder14 yes a normal for loop can be used with the same block of code even for the conventional for loop. either for(let index in array){const item = array[index]; //rest same code block from original answer } or for(let index=0; index<array.length; index++){const item=array[index]; //rest same code block from original answer} can be used!
|
2

You can use reduce() to return object as result with both count and start-end index for each name.

var arr = [{"id":"1","name":"A","address":"A"},{"id":"2","name":"A","address":"B"},{"id":"3","name":"A","address":"C"},{"id":"4","name":"B","address":"A"},{"id":"5","name":"B","address":"B"},{"id":"6","name":"C","address":"A"},{"id":"7","name":"C","address":"B"},{"id":"8","name":"C","address":"C"}]

var l = null;

var result = arr.reduce(function(r, e, i) {
  if (!r[e.name]) {
    l = e.name;
    r[e.name] = {
      count: 1,
      index: i.toString()
    }
  } else {
    if (arr[i + 1] && arr[i + 1].name != l || !arr[i + 1]) r[e.name].index += '-' + i;
    r[e.name].count++
  }
  return r;
}, {})

console.log(result)

Comments

1

You can use ES6 Array.from() method.

Try this it will work as per your expectation :

var a = [
    {id:"1", name:"A", address:"A"},
    {id:"2", name:"A", address:"B"},
    {id:"3", name:"A", address:"C"},
    {id:"4", name:"B", address:"A"},
    {id:"5", name:"B", address:"B"},
    {id:"6", name:"C", address:"A"},
    {id:"7", name:"C", address:"B"},
    {id:"8", name:"C", address:"C"}];

// fetch all the name property value into an array.
var nameArr = Array.from(a, x => x.name);

var obj = {};

for (var i = 0; i < nameArr.length; i++) {
    var elem = nameArr[i];

    // if we haven't seen the element yet, 
    // we have to create a new entry in the map
    if (!obj[elem]) {
        obj[elem] = [i];
    }
    else {
        if(obj[elem].indexOf(nameArr.lastIndexOf(elem)) == -1) {
          // otherwise append to the existing array
          obj[elem].push(nameArr.lastIndexOf(elem));
        }
    }
}
 
for (var i in obj) {
  console.log('index ' +obj[i].join('-')+ ' => "'+i+'"');
}

Comments

0

For counting the duplicates, you can use Underscore.js which has a method called _.groupBy()(see this). It gives you an object of key-value pairs where keys are the value you want to check for duplication and value is the array of objects what have that key. Its like this -

  var groupedData = _.groupBy(array, function(elem){
       return elem.name; //here you can specify whichever key you want to check duplicates for
  });

  console.log(groupedData['A'].length);

Comments

0

You could use Array#reduce and check the predecessor if the name is not the same or at the first index, then create a new array with the index information.

var data = [{ id: "1", name: "A", address: "A" }, { id: "2", name: "A", address: "B" }, { id: "3", name: "A", address: "C" }, { id: "4", name: "B", address: "A" }, { id: "5", name: "B", address: "B" }, { id: "6", name: "C", address: "A" }, { id: "7", name: "C", address: "B" }, { id: "8", name: "C", address: "C" }],
    groups = data.reduce(function (r, a, i, aa) {
        (!i || aa[i - 1].name !== a.name) && r.push([i, i, a.name]);
        r[r.length - 1][1] = i;
        return r;
    }, []);

console.log(groups);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

0

You could try to use the groupBy method in underscore. It doesn't do the full job of formatting it, but gets you to a good place to carry on with it.

var data = [{ id: "1", name: "A", address: "A" }, { id: "2", name: "A", address: "B" }, { id: "3", name: "A", address: "C" }, { id: "4", name: "B", address: "A" }, { id: "5", name: "B", address: "B" }, { id: "6", name: "C", address: "A" }, { id: "7", name: "C", address: "B" }, { id: "8", name: "C", address: "C" }],

groups = _.groupBy(data, 'name');
console.log(groups);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

2 Comments

I can't use external libs.
@silent_coder14 that's a shame, the above is very handy and readable. I hope it's useful for future reader's with the same problem but not the same restrictions
0

You can do more simply using filter method in combination with forEach.

The first step is to find out the unique names from your array. This can be achieved using Set method from ES6.

var names=[...new Set(array.map(a=>a.name))];

or

UPDATE

 names=array.map(a=>a.name).filter(function (x, i, a) { 
      return a.indexOf(x) == i; 
 });

Then you should use filter method, which accepts a callback provided function , in order to get the items which have name equals to one element from names array.

var array= [
    {id:"1", name:"A", address:"A"},
    {id:"2", name:"A", address:"B"},
    {id:"3", name:"A", address:"C"},
    {id:"4", name:"B", address:"A"},
    {id:"5", name:"B", address:"B"},
    {id:"6", name:"C", address:"A"},
    {id:"7", name:"C", address:"B"},
    {id:"8", name:"C", address:"C"}];
    
var names=[...new Set(array.map(a=>a.name))];
names.forEach(function(item){
  indexes=array.map(function(item,i){
     item["index"]=i;
     return item;
  })
  .filter(a=>a.name==item)
  .map(a=>a.index);
  console.log(indexes[0]+'-'+indexes[indexes.length-1]+'->'+item+', count= '+indexes.length);
});

1 Comment

nope, I can't use ... new Set. It gives me syntax error.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.