Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 04.07.2013, 15:16
KumoKairo вне форума Посмотреть профиль Отправить личное сообщение для KumoKairo Найти все сообщения от KumoKairo
  № 1  
Ответить с цитированием
KumoKairo
 
Аватар для KumoKairo

Регистрация: Jan 2013
Сообщений: 550
Записей в блоге: 1
Post Логические операции как способ визуального упрощения кода

Добрый день, история такая:
Понадобился мне алгоритм быстрой проверки массива на одинаковые элементы с последующим удалением дубликатов. На Starkoverflow нашел следующий код, предназначенный для работы с массивом из строк (товарищу надо было удалить одинаковые имена):
Код AS3:
var a:Array = ["Tom", "John", "Susan", "Marie", "Tom", "John", "Tom", "Eva"];
a.sort();
var i:int = 0;
while(i < a.length) {
    while(i < a.length+1 && a[i] == a[i+1]) {
        a.splice(i, 1);
    }
    i++;
}
В данном случае опустим вопрос про nested loops и предварительную сортировку, так как суть в конце концов не в этом.

В моем случае объекты в массиве - не строки, а именно объекты с несколькими полями. Удалять мне надо по id, то есть дополнительно нужно указывать, допустим, a[i].id
Но в этом алгоритме есть хитрость, которая подтолкнула меня получше разобраться с булевыми операторами в AS3 (надо же подкрутить этот алгоритм под свой код)
Условие
Код AS3:
a[i] == a[i+1]
не выполняется в двух случаях - когда [i]a и a[i+1] не равны, или если a[i+1] является null. По этой причине нельзя просто сделать так:
Код AS3:
var a:Array = [{id:"1"}, {id:"2"}, {id:"3"}, {id:"1"}, {id:"4"}, {id:"3"}, {id:"5"}, {id:"2"}];
var i:int = 0;
while(i < a.length) {
    while(i < a.length+1 && a[i].id == a[i+1].id) {
        a.splice(i, 1);
    }
    i++;
}
Потому что в конце цикла вылезет рантайм ошибка обращения к несуществующему полю несуществуюшего объекта.
Мне стало интересно, может ли логическа операция && возвратить существующее (не null) значение какого-либо параметра (Как это используется в Lua, например). Открываем документацию, читаем:
Цитата:
&& logical AND
Возвращает выражение expression1, если оно имеет значение false или может быть преобразовано в false, в противном случае возвращает выражение expression2. Значениями, которые могут быть преобразованы в false, являются 0, NaN, null и undefined. Если в качестве expression2 используется вызов функции, функция не будет вызвана, если expression1 принимает значение false.
Отлично, что надо (подумал я) и написал:
Код AS3:
var a:Array = [{id:"1"}, {id:"2"}, {id:"3"}, {id:"1"}, {id:"4"}, {id:"3"}, {id:"5"}, {id:"2"}];
var i:int = 0;
while(i < a.length) {
    while(i < a.length+1 && a[i].id == (a[i+1] && a[i+1].id)) {
        a.splice(i, 1);
    }
    i++;
}
По идее (по крайней мере по-моему) такой способ должен был бы заработать:
если expression1 (a[i+1]) принимает значение false или может быть преобразовано в false (в нашем случае в false преобразовывается null), то оператор возвращает это expression1, условие становится как в оригинальном алгоритме:
Код AS3:
a[i].id == null
если же a[i+1] не null, то возвращаем a[i+1].id, сравниваем с a[i] и все счастливы.

Но все было бы слишком просто. По неизвестной мне причине такой способ работать отказался и я решил пойти дальше - протрейсить эти a[i+1].id следующим образом:
Код AS3:
var a:Array = [{id:"1"}, {id:"2"}, {id:"3"}, {id:"1"}, {id:"4"}, {id:"3"}, {id:"5"}, {id:"2"}];
var i:int = 0;
while(i < a.length) {
    trace(a[i+1] && a[i+1].id);
    while(i < a.length+1 && a[i].id == (a[i+1] && a[i+1].id)) {
        a.splice(i, 1);
    }
    i++;
}
В логе трейса исправно выводились нужные id до конца, в конце же, так же по логике, в лог вывело null.
Очень странно - оператор работает правильно, сравниваем вроде одно и то же, а логика не работает
Но если попробовать потрейсить так:
Код AS3:
var a:Array = [{id:"1"}, {id:"2"}, {id:"3"}, {id:"1"}, {id:"4"}, {id:"3"}, {id:"5"}, {id:"2"}];
var i:int = 0;
while(i < a.length) {
    trace(a[i].id == (a[i+1] && a[i+1].id));
    while(i < a.length+1 && a[i].id == (a[i+1] && a[i+1].id)) {
        a.splice(i, 1);
    }
    i++;
}
То почти все время выводится false и иногда выводится 1 true (а в моем массиве у меня порядка 20ти - 30ти одинаковых элементов)

Итак, вопрос:
Что я упускаю?

Отвечать будет Друзь?

Старый 04.07.2013, 15:31
maxkar вне форума Посмотреть профиль Отправить личное сообщение для maxkar Найти все сообщения от maxkar
  № 2  
Ответить с цитированием
maxkar

Регистрация: Nov 2010
Сообщений: 497
Цитата:
Что я упускаю?
Там в исходном примере опечатка. Должно быть
Код AS3:
while(i < a.length - 1 && a[i].id == a[i+1].id)
После этого никакие приседания не нужны.

А вообще вы путаете AS3 и LISP/LUA/PYTHON и прочие языки. В AS оператор && возвращает true/false, а не значение второго аргумента.

Старый 04.07.2013, 15:33
KumoKairo вне форума Посмотреть профиль Отправить личное сообщение для KumoKairo Найти все сообщения от KumoKairo
  № 3  
Ответить с цитированием
KumoKairo
 
Аватар для KumoKairo

Регистрация: Jan 2013
Сообщений: 550
Записей в блоге: 1
maxkar, а как же тесты и документация?
попробуйте потрейсить
Код AS3:
var a:Array = [{id:"1"}, {id:"2"}, {id:"3"}, {id:"1"}, {id:"4"}, {id:"3"}, {id:"5"}, {id:"2"}];
var i:int = 0;
while(i < a.length) {
    trace(a[i+1] && a[i+1].id); //Вот здесь будет выводить id, если элемент существует и null, если элемент null
    while(i < a.length+1 && a[i].id == (a[i+1] && a[i+1].id)) {
        a.splice(i, 1);
    }
    i++;
}
все работает как и написано - возвращает второй операнд если первый true или первый операнд, если первый false

Цитата:
Returns expression1 if it is false or can be converted to false, and expression2 otherwise.

Старый 04.07.2013, 15:57
maxkar вне форума Посмотреть профиль Отправить личное сообщение для maxkar Найти все сообщения от maxkar
  № 4  
Ответить с цитированием
maxkar

Регистрация: Nov 2010
Сообщений: 497
Ну в таком случае все правильно. У вас в вашем массиве нет двух элементов с одинаковым ID подряд. И только где-то на границе массива (i == a.length) вы получаете два null'а.

Цитата:
Что я упускаю?
Цитата:
В данном случае опустим ... предварительную сортировку, так как суть в конце концов не в этом.
Она важна. Без нее указанный код работать просто не будет.

Старый 04.07.2013, 15:59
belv вне форума Посмотреть профиль Отправить личное сообщение для belv Найти все сообщения от belv
  № 5  
Ответить с цитированием
belv
[+1 16.07.13]
[+4 16.07.13]

Регистрация: Oct 2005
Сообщений: 217
Вы упускаете сортировку массива ,вот так у меня работает
Код AS3:
var a:Array = [{id:"1"}, {id:"3"}, {id:"2"}, {id:"3"}, {id:"1"}, {id:"3"}, {id:"4"}, {id:"3"}, {id:"5"}, {id:"2"}];
var i:int = 0;
a.sort(sortOnID);
function sortOnID(a:Object, b:Object):Number {
    var aID:Number = a.id;
    var bID:Number = b.id;
 
    if(aID > bID) {
        return 1;
    } else if(aID < bID) {
        return -1;
    } else  {
        return 0;
    }
}
while(i < a.length) {
  	trace(a[i] && a[i].id);
    while(i < a.length+1 && a[i].id == (a[i+1] && a[i+1].id)) {
       a.splice(i, 1);
    }
    i++;
}

Старый 04.07.2013, 16:09
KumoKairo вне форума Посмотреть профиль Отправить личное сообщение для KumoKairo Найти все сообщения от KumoKairo
  № 6  
Ответить с цитированием
KumoKairo
 
Аватар для KumoKairo

Регистрация: Jan 2013
Сообщений: 550
Записей в блоге: 1
Да, с сортировкой я что-то перескочил.
Цитата:
Она важна. Без нее указанный код работать просто не будет.
Той фразой я хотел пресечь всевозможные разговоры про уменьшение скорости выполнения из-за сортировки и вложенных циклов)

belv, угу, спасибо!

Старый 04.07.2013, 16:51
PsixokoT вне форума Посмотреть профиль Отправить личное сообщение для PsixokoT Найти все сообщения от PsixokoT
  № 7  
Ответить с цитированием
PsixokoT

Регистрация: May 2008
Сообщений: 63
Если вам нужно иметь список объектов без повторений то вместо вот таких вот сориторовок/удалений, не проще ли данные изначально хранить в ассоциативном массиве(словаре)?

Старый 04.07.2013, 17:03
KumoKairo вне форума Посмотреть профиль Отправить личное сообщение для KumoKairo Найти все сообщения от KumoKairo
  № 8  
Ответить с цитированием
KumoKairo
 
Аватар для KumoKairo

Регистрация: Jan 2013
Сообщений: 550
Записей в блоге: 1
Кстати да, совсем забыл про словарь...

на самом деле там выйгрыш по производительности будет не особо заметен, ибо массив из максимум 10ти элементов, и это в худшем случае.
Что так меньше одной мс на все операции, что по другому, тут больше идейный вопрос синтаксиса и логики был

Спасибо за наводку в любом случае)


Последний раз редактировалось KumoKairo; 04.07.2013 в 19:50.
Создать новую тему Ответ Часовой пояс GMT +4, время: 02:52.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Теги
&& , логические операции
Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


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


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.