Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Поиск по массиву объектов (https://javascript.ru/forum/misc/49427-poisk-po-massivu-obektov.html)

Georrg 12.08.2014 20:36

Поиск по массиву объектов
 
Есть массив объектов. Я знаю ключ к нужному объекту(key=137),но не знаю который это объект в массиве(нужно раза 3 прочитать чтобы понять суть). Можно запустить перебор всего массива,но это долго(это для всплывающего окна пользователя). Иначе окно будет всплывать вечность. Как выбрать объект из массива, зная его ключ. Скрин прилагается:

animhotep 12.08.2014 20:44

key это значение свойства объекта, он к массиву слабо относится
думаю придётся все перебирать

tsigel 12.08.2014 20:47

ну если массив упорядоченный по номеру то очень просто)

Даже если key не соответсвует номеру массива в упорядоченном массиве можно использовать алгоритм бинарного поиска

Можете упорядочить массив и будет вам счастье.

Упорядочевать массив врятли придется часто, так что там тормоза не критичны

tsigel 12.08.2014 20:56

Кстати если так нужно часто искать метку то почему бы не поменять формат? Сделать асоциативный массив по ключам. Или если не жалко память то можно сделать карту массива что обеспечит мгновенный поиск.

Карта массива:
var arr = [
  {
      key: 1,
      label: "trololo1" 
  },
  {
      key: 2,
      label: "trololo2" 
  }
];

var map = {
   1: 0,
   2: 1
};

alert(arr[map[1]].label);


Естественно что карта должна генерироваться налету, но идея должна быть понятна.

Pavel M. 13.08.2014 17:54

может быть Array.prototype.filter
будет быстро искать?

var arr = [
  {key: 3, label: '333333333'},
  {key: 137, label: '555'},
  {key: 2, label: '222222'}
],
myArr = arr.filter(function (item) {
  return (item.key === 137);
});

alert(JSON.stringify(myArr));

Aetae 13.08.2014 18:32

Pavel M., мечтай.)

tsigel 13.08.2014 20:49

Pavel M.,
Если уж нужен 1 элемент и использовать нативные методы то надо пользовать some, потому что его можно остановить найдя нужный элемент, а filter пройдет весь массив целиком.

Aetae 13.08.2014 21:01

tsigel, в ff есть ещё find:) :
var arr = [
  {key: 3, label: '333333333'},
  {key: 137, label: '555'},
  {key: 2, label: '222222'}
],
myArr = arr.find(el => el.key === 137);
 
alert(JSON.stringify(myArr));
но цикл всё равно быстрее.)

tsigel 13.08.2014 21:02

Aetae,
Цикл for быстрее чем some?

то есть
var arr = [...];
var someKey = "somekey"

for (var i=0,l=arr.length;i<l;i++) {
   if (arr[i].key==someKey) {
      //...
      break;
   }
}


быстрее чем

var arr = [...];
var someKey = "somekey"


arr.some(function (el) {
   if (el.key==someKey) {
      //...
      return true;
   }
});


Вроде бы писали везде что эти нативные методы не уступают обычным переборам. Точнее я читал что они иногда даже быстрее, а иногда - медленнее, но не значительно.

nerv_ 14.08.2014 01:45

<script src="http://sugarjs.com/release/current/sugar-full.min.js"></script>
<script>
var arr = [
  {key: 3, label: '333333333'},
  {key: 137, label: '555'},
  {key: 2, label: '222222'}
];

alert(JSON.stringify(arr.find({key: 137})));
</script>

kobezzza 14.08.2014 08:27

Цитата:

но цикл всё равно быстрее.)
От VM зависит. В IE11 нет разницы как правило.

***

А по теме: Collection

Работает быстрее итераторов, циклов и всех известных библиотек и со всеми возможными типами данных :)

Pavel M. 14.08.2014 12:55

действительно
попробовал скорость filter и обычного цикла на большом массиве
в Хроме, FF, IE11

у меня цикл быстрее в разы (см. в console)
спасибо Aetae - не знал

var i,
	maxItems = 1e6,
	arr = [],
	needKey = 500137, // где-то в середине
	myArr;

// генерим массив
for (i = 0; i < maxItems; i += 1) {
  arr.push({key: i, label: i + ''});
}

// test filter
console.time('filter');

myArr = arr.filter(function (item) {
  return (item.key === needKey);
});

console.timeEnd('filter');

alert(JSON.stringify(myArr));


// test цикл
myArr = [];

console.time('for');

for (i = 0; i < arr.length; i += 1) {
   if (arr[i].key === needKey) {
	  myArr.push(arr[i]);
	  break;
   }
}

console.timeEnd('for');

alert(JSON.stringify(myArr));

kobezzza 14.08.2014 13:00

Pavel M. никогда не делай бенчмарки через консоль отладчика, т.к. он отключает использование JIT компилятора и результат замеров может значительно отличаться.

ixth 14.08.2014 13:04

Цитата:

Сообщение от Pavel M. (Сообщение 325827)
действительно
попробовал скорость filter и обычного цикла на большом массиве
в Хроме, FF, IE11

у меня цикл быстрее в разы (см. в console)
спасибо Aetae - не знал

Потому что методика тестирования хромает. filter обходит весь массив, for — нет. Можно попробовать так:

var i,
	maxItems = 1e6,
	arr = [],
	needKey = 500137, // где-то в середине
	myArr;

// генерим массив
for (i = 0; i < maxItems; i += 1) {
  arr.push({key: i, label: i + ''});
}

// test filter
console.time('some');

myArr = [];
arr.some(function (item) {
  if (item.key === needKey) {
    myArr = [item];
    return true;
  }
  return false;
});

console.timeEnd('some');

alert(JSON.stringify(myArr));


// test цикл
myArr = [];

console.time('for');

for (i = 0; i < arr.length; i += 1) {
   if (arr[i].key === needKey) {
	  myArr.push(arr[i]);
	  break;
   }
}

console.timeEnd('for');

alert(JSON.stringify(myArr));


some у меня отрабатывает в полтора раза быстрее filter, но все еще в два раза медленнее, чем for:

Цитата:

some: 23.802ms VM1460:24
for: 14.023ms VM1460:41

ixth 14.08.2014 13:07

Цитата:

Сообщение от kobezzza (Сообщение 325828)
Pavel M. никогда не делай бенчмарки через консоль отладчика, т.к. он отключает использование JIT компилятора и результат замеров может значительно отличаться.

Как насчет jsperf? Первое, что нагуглилось: http://jsperf.com/array-some-vs-loop

kobezzza 14.08.2014 13:11

Цитата:

Сообщение от ixth (Сообщение 325833)
Как насчет jsperf? Первое, что нагуглилось: http://jsperf.com/array-some-vs-loop

jsperf неплохой сервис, но многие не понимают, что примеры для теста он сам запускает в цикле, т.е. когда мы тестируем циклы и итераторы, то у нас на самом деле тестируется выполнение итераторов и циклов внутри цикла, а если более точно сказать - скорость инициализации + скорость выполнения и это может полностью исказить результат теста.

Для тестирования именно скорости итераций лучше самом написать простой тест, как например тут https://github.com/kobezzza/Collecti...ter/benchmarks

Цитата:

some у меня отрабатывает в полтора раза быстрее filter, но все еще в два раза медленнее, чем for:
Я хоть убей не понимаю, зачем костылить в своём коде и делать оптимизации, которые "завтра" с обновлением VM могут стать абсолютно бесполезными (я уже молчу про части, где часть на циклах, а часть итераторах), но при этом делают наш код ужасным. Есть же готовые либы, которые инкапсулируют в себе все все оптимизации и работают супер быстро, но при этом дают простой и удобный интерфейс, и не нужно самому ничего изобретать.

Я уже молчу про то, что нативные интерфейсы алгоритмически убоги и работают только с массивами. Очень частый пример, нужно сделать фильтр, потом мап, а потом взять первые 10 результатов, т.е.

filter().map().slice()


Алгоритмическая сложность просто ужасна, думаю всем это понятно. Гораздо лучше сделать:

map(..., {filter(), slice()})


Т.е. всё в один проход вместо 3-х

ixth 14.08.2014 13:26

Цитата:

Сообщение от kobezzza (Сообщение 325834)
Я хоть убей не понимаю, зачем костылить в своём коде и делать оптимизации, которые "завтра" с обновлением VM могут стать абсолютно бесполезными (я уже молчу про части, где часть на циклах, а часть итераторах), но при этом делают наш код ужасным.

Ну, лично мне вообще все равно, это просто спортивный вопрос: правда ли, что Array extras (или как там правильно) быстрее, чем простой for?

Цитата:

Сообщение от kobezzza (Сообщение 325834)
Гораздо лучше сделать:

map(..., {filter(), slice()})


Т.е. всё в один проход вместо 3-х

Это какая-то новая экма? Потому что я в ней ни в зуб ногой. Что эта запись означает?

kobezzza 14.08.2014 13:36

Цитата:

Это какая-то новая экма? Потому что я в ней ни в зуб ногой. Что эта запись означает?
Это псведокод :)

С использованием либы Collection это будет выглядеть так:

$C(/* тут наш объект для итераций */).map(function () {
    ...
}, {
    filter: function () {
        ...
    },

    from: 100,
    count: 10
});


Цитата:

Ну, лично мне вообще все равно, это просто спортивный вопрос: правда ли, что Array extras (или как там правильно) быстрее, чем простой for?
Это слишком сложный вопрос, т.к. он привязан к примеру и мощности JIT VM, т.е. однозначного ответа нет.

kobezzza 14.08.2014 13:55

Цитата:

kobezzza,
Я бы использовал либу для итераций еслибы было какое-то проседание в скорости работы кода. Мне это не требуется, у меня нет огромных объемов данных и необходимости быстро их итерировать.
Ну у меня просто другой подход. Я всегда юзаю либу и просто не думаю о количестве и типе данных, т.к. оно всегда будет работать быстро :)

tsigel 14.08.2014 14:06

kobezzza,
Ну это потому что ты написал эту либу)))

Я тоже таскаю некоторые свои штуки из проекта в проект)
А подключать либу на 17кб просто чтобы не париться - неохота)
Я и так не парюсь)

Pavel M. 14.08.2014 14:07

Цитата:

Сообщение от kobezzza
никогда не делай бенчмарки через консоль отладчика, т.к. он отключает использование JIT компилятора и результат замеров может значительно отличаться

сделал без консоли

результат почти тот же в Хроме, FF

var timeStart,
	i,
	maxItems = 1e6,
	arr = [],
	needKey = 500137, // где-то в середине
	myArr;

// генерим массив
for (i = 0; i < maxItems; i += 1) {
  arr.push({key: i, label: i + ''});
}

// test filter
timeStart = +(new Date());
myArr = arr.filter(function (item) {
  return (item.key === needKey);
});

alert('filter ms: ' + (new Date() - timeStart));

// test цикл
myArr = [];
timeStart = +(new Date());

for (i = 0; i < arr.length; i += 1) {
   if (arr[i].key === needKey) {
	  myArr.push(arr[i]);
	  break;
   }
}

alert('for ms: ' + (new Date() - timeStart));

kobezzza 14.08.2014 14:16

Цитата:

А подключать либу на 17кб просто чтобы не париться - неохота)
Во первых из коробки есть аж 3 сборки, и одна из них весит 9кб и включает только итераторы. Во вторых очень просто делать свои сборки и обо всём этом написано в доке.

Цитата:

Ну это потому что ты написал эту либу)))
Я юзаю много либ, просто эта написана мной, но это не суть, я просто привёл как пример.

tsigel 14.08.2014 14:16

Pavel M.,
Ваш тест алгоритмически не верен. Фильт проходит весь массив а фор - часть. Хотите такой тест сравнивайте с some

kobezzza 14.08.2014 14:18

Цитата:

результат почти тот же в Хроме, FF
Иногда мне кажется, что меня не слушают...

Цитата:

т.к. он отключает использование JIT компилятора и результат замеров может значительно отличаться.
т.е. чем сложнее пример, тем выше может быть разница.

Pavel M. 14.08.2014 14:59

Цитата:

Сообщение от tsigel
Ваш тест алгоритмически не верен. Фильт проходит весь массив а фор - часть.

пробовал и for крутить до конца - все равно for получается быстрее в популярных современных браузерах


Часовой пояс GMT +3, время: 02:01.