подсчет общего количества дубликатов в массиве js

#javascript

#javascript

Вопрос:

Я перебираю все имена классов в моем html-теле. Я бы хотел сохранить classname со значением textSize. Каждый раз, когда для данного classname появляется повторяющееся значение, я хочу увеличить его textSize .

 $("*").each(function() {
    classname = $(this).get(0).className;
    myarray.push({"className" : classname, "textSize" : 5});
  

Здесь я пытаюсь отсортировать имена классов, а затем получить количество для каждого дубликата:

 myarray.sort();
var current = null;
var dupCount = 0;

for (var i = 0; i < myarray.length-1; i  ) {
    if (myarray[i]["className"] !== "") {
        if (myarray.indexOf(myarray[i]["className"]) == -1) {
            log(myarray[i]["className"]);
        }
        else {
            log("DUP");
            myarray[i]["textSize"] = myarray[i]["textSize"]  = 5;
            dupCount  ;
        }
    }
}
  

log(myarray[i]["className"]); , показанный на изображении ниже, четко показывает дубликаты:

введите описание изображения здесь

Тем не менее, log("DUP"); никогда не вызывается один раз. Почему это так?

Более того, почему они не myarray.sort(); сортируются по алфавиту? Если бы это было сделано, я мог бы просто if (myarray[i]["className"] === myarray[i ]["className"]) { проверить, равно ли значение следующему значению в массиве. Но сортировка не работает.


Редактировать:

Итак, при выполнении цикла я должен иметь возможность изменять css для каждого имени класса, верно?

 for(var classname in classes) {
    console.log(classes[classname].textSize);
    var $val = $(classes[classname]);                       
    $val.css({
        "color" : "blue",
        "fontSize": $val.textSize "px"
    });
}
  

Это не работает, хотя console.log(classes[classname].textSize); дает размеры текста для каждого элемента

Ответ №1:

Попробуйте использовать объект вместо массива, используя имена классов в качестве ключей:

 var classes = {};

$("*").each(function() {
    var classname = $(this).get(0).className;
    var c = classes[classname] || 
        (classes[classname] = { className: classname, textSize: 0 });
    c.textSize  = 5;
});

for(var classname in classes) {
    console.log(classes[classname]);
}
  

Помните, что любой элемент может иметь несколько классов. Если вы хотите учесть это, вам придется разделить имена классов:

 $("*").each(function() {
    var classnames = $(this).get(0).className.split(' ');
    for(var i=0; i<classnames.length; i  ) {
        var classname = classnames[i];
        var c = classes[classname] || 
            (classes[classname] = { className: classname, textSize: 0 });
        c.textSize  = 5;
    }
});
  

Посмотрите эту демонстрацию: http://jsfiddle.net/FSBhv /

ОБНОВЛЕНИЕ: ОП пояснил, что он хочет установить размер текста для элементов на основе количества элементов, имеющих этот класс. Для этого потребуется несколько иной подход (на самом деле нам придется хранить элементы):

 var eltsByClass = {};

$("*").each(function() {
    var $this = $(this);
    $this.get(0).className.split(' ').forEach(function(cname) {
        var c = eltsByClass[cname] || 
            (eltsByClass[cname] = []);
        c.push($this.get(0));
    });
});

for(var cname in eltsByClass) {
    var elts = eltsByClass[cname];
    $(elts).css('font-size', (elts.length   1) * 5   'px');
}
  

Комментарии:

1. Итан, ты можешь помочь мне понять, что здесь происходит? var c = classes[classname] || (classes[classname] = { className: classname, textSize: 0 });

2. Конечно. classes это объект, который содержит запись (другой объект) для каждого найденного имени класса. Либо запись уже существует ( classes[classname] является правдивой и c устанавливается на нее), либо она еще не создана, и в этом случае мы создаем и назначаем ее на том же шаге : classes[classname] = { className: classname, textSize: 0 } .

3. Хорошо, спасибо! Я обновил выше. Я пытаюсь установить css для имен классов. Чем чаще они встречаются, тем больше увеличивается размер текста для этого имени класса. По какой-то причине css не устанавливается

4. О, извините, эта часть была мне непонятна. Это немного более сложная проблема: сначала вы должны посчитать их все, а ЗАТЕМ установить их размер. Я обновлю свой ответ.

Ответ №2:

Храните свои данные в объекте, а не в массиве. И это можно упростить как:

 var classes = {};

$("*").each(function() {
    var classname = $(this).get(0).className;
    classes[classname] = (classes[classname] || 0)   5;
});

for(var classname in classes) {
    console.log(classname   " textSize:"   classes[classname]);
}
  

Комментарии:

1. $(this).get(0).className против this.className ?

Ответ №3:

myarray.indexOf(myarray[i]["className"]) это проблема.

Вы знаете, что myarray он содержит только объекты, но вы запрашиваете позицию строки в этом списке. Это никогда не вернет ничего, кроме -1 .

Рассмотрите возможность использования второго массива для хранения количества частот, вместо того, чтобы пытаться использовать оба myarray .

 var frequency = {};

myarray.forEach(function (i) {
  frequency[i.className] = frequency[i.className] || 0 
  frequency[i.className]  ;
}
  

Комментарии:

1. И что происходит, когда у меня есть <div class="constructor">...</div> ? 🙂

Ответ №4:

Это поможет вам отсортировать массив в алфавитном порядке на основе classname

     var myarray=[];
$("*").each(function() 
{
    classname = $(this).get(0).className;
    myarray.push({"className" : classname, "textSize" : 5});
});


function compare(a,b) 
{
  if (a.className < b.className)
     return -1;
  if (a.className > b.className)
    return 1;
  return 0;
}       

myarray.sort(compare);