Страницы

Поиск по вопросам

Показаны сообщения с ярлыком объекты. Показать все сообщения
Показаны сообщения с ярлыком объекты. Показать все сообщения

понедельник, 30 марта 2020 г.

Объекты первого класса Python - полезные примеры новичку

#python #объекты


В книге Д.Бизли «Python. Подробный справочник» есть такое суждение:


  Тот факт, что все объекты в языке Python являются объектами первого
  класса, зачастую недооценивается начинающими программистами, тогда как
  это позволяет писать очень компактные и гибкие программы. Например,
  предположим, что имеется текстовая строка, такая как
  “GOOG,100,490.10”, и вам необходимо превратить ее в список полей,
  попутно выполнив необходимые преобразования типов. Ниже приводится
  грамотный способ реализации такого преобразования: создается список
  типов (которые также являются объектами первого класса) и выполняется
  несколько простых операций по обработке списка:


>>> line = "GOOG,100,490.10"
>>> field_types = [str, int, float] 
>>> raw_fields = line.split(',') 
>>> fields = [ty(val) for ty,val in zip(field_types,raw_fields)]  
>>> fields 



  [‘GOOG’, 100, 490.10000000000002] 


A есть ли еще какие полезные "для новичка" примеры использования этой особенности
языка Python? 

А то кажется, что это больше похоже на источник головоломных ошибок.
    


Ответы

Ответ 1



Мне кажется в данном контексте можно сделать несколько показательных примеров с функциями, которые можно: передавать в качестве аргументов возвращать сохранять в переменную (как ссылку на функцию) Пример: пусть нам дана двумерная матрица и необходимо найти некоторые характеристики (минимум, максимум и среднее) для каждой строки: In [15]: import random In [16]: A = [[random.randint(0, 10) for _ in range(10)] for _ in range(10)] In [17]: A Out[17]: [[6, 9, 6, 2, 0, 4, 3, 4, 5, 7], [2, 6, 6, 0, 8, 8, 6, 5, 2, 5], [10, 6, 0, 10, 1, 5, 8, 10, 9, 9], [3, 0, 4, 0, 0, 2, 1, 2, 8, 6], [5, 10, 8, 7, 8, 3, 0, 5, 0, 8], [9, 7, 2, 0, 8, 5, 0, 4, 4, 9], [9, 3, 8, 6, 6, 10, 5, 0, 0, 1], [7, 3, 2, 4, 5, 0, 0, 9, 0, 10], [8, 7, 10, 2, 6, 7, 2, 6, 2, 1], [3, 3, 1, 1, 1, 4, 8, 0, 3, 4]] In [18]: funcs = [min, max, lambda x: sum(x)/len(x)] In [19]: [[f(lst) for f in funcs] for lst in A] Out[19]: [[0, 9, 4.6], [0, 8, 4.8], [0, 10, 6.8], [0, 8, 2.6], [0, 10, 5.4], [0, 9, 4.8], [0, 10, 4.8], [0, 10, 4.0], [1, 10, 5.1], [0, 8, 2.8]] теперь для того, чтобы добавить новые характеристики, например сумму значений в каждой строке, достаточно будет добавить имя функции в список funcs - остальной код остается неизменным: In [20]: funcs.append(sum) In [21]: [[f(lst) for f in funcs] for lst in A] Out[21]: [[0, 9, 4.6, 46], [0, 8, 4.8, 48], [0, 10, 6.8, 68], [0, 8, 2.6, 26], [0, 10, 5.4, 54], [0, 9, 4.8, 48], [0, 10, 4.8, 48], [0, 10, 4.0, 40], [1, 10, 5.1, 51], [0, 8, 2.8, 28]]

воскресенье, 15 марта 2020 г.

Обращение к объекту, как к массиву

#javascript #объекты #index


Есть ли простой способ обратиться к ключу объекта по его индексу? Может в Underscore
есть магические методы?

Вопрос возник на фоне такой задачи. Есть объект:

plane: {
    432: {
        columns: {
            543: {
                name: 'lolo'
            },
            984: {
                name: 'lala'
            },
            ...
        }
    },
    ...
}


Где среди n-го количества plane, и n-го количества column нужно выбрать первый plane
и первый column внутри него.

Как сделать это проще всего?
    


Ответы

Ответ 1



Хотя ES6 обеспечивает определённый порядок ключей при обходе, гораздо правильнее и удобнее использовать массив, положив тот ключ внутрь объекта, например, в поле id. Но если уж очень хочется, то можно сделать так (как-нибудь сократив название): Object.prototype.getByKeyIndex = function (i) { var key = Object.keys(this)[i]; return key && this[key]; } Тогда на объекте из вопроса будет такое: plane.getByKeyIndex(0).columns.getByKeyIndex(1).name // "lala" Вроде, более-менее нормально выглядит. Ключ сохраняется в переменную и проверяется, чтобы в таком варианте получилось undefined: ({ undefined: 42 }).getByKeyIndex(256) Я новичок и хочу у Вас спросить - хорошо ли изменять прототип нативных объектов? Что будет если я добавлю метод, а после кто-то другой тоже Ваш ответ увидит и решит добавить свой, но с таким же методом? В большинстве случаев изменять прототип Object'а не очень хорошо. Но для защиты от прототипных свойств принято фильтровать for-in через hasOwnProperty. Другой вариант - добавлять в прототип не так, как это сделал я, а через скрытое свойство, чтобы оно не перебиралось. Если двое добавили одинаковое свойство, то одно из них перезапишет другое. По идее, последнее добавленное должно перезаписать предыдущее, но можно пошаманить с readonly, чтобы осталось более раннее. В любом случае, такая ситуация заведомо плохая и лучше в неё не попадать. Если двое добавят одну и ту же функцию под разными именами, то будет две функции. Тут вроде всё очевидно и вопросов вызывать не должно. Что касается того, стоит ли изменять прототип. Если это изменение упростит половину кода, то, на мой взгляд, это оправдано. Если же это делается ради одной функции, то, скорее всего, нет. Для любых глобальных изменений стоит проявлять разумность и осторожность.

Ответ 2



Object.keys(obj)[index] например, где obj - объект в котором мы ищем. Не вполне ослоустойчиво, будет работать в IE 9+. Можно использовать _.keys(obj)[index] из underscore, это все сократит на пару символов =). Кстати я не уверен, что лексикографический (да и вообще какой-то) порядок ключей нам гарантирован при этом, скорее всего массив ключей надо дополнительно сортировать.

Ответ 3



TL;DR: Порядок ключей в объекте JS не гарантируется. Для сохранения порядка лучше юзать массив. Из личного опыта: Браузеры стараются придерживаться того порядка полей, в котором они были определены. Но на это рассчитывать не стоит. Например, при общении с сервером через WebApi порядок может сбится. Практический пример: в python объекты JSON преобразуется в словарь dict. А в нем уж точно порядок полей не сохраняется и может поменятся произвольно при сериализации обратно в JSON. Объекты JS - это хеш-таблицы, т.е. пары ключ-значение. Порядок пар в такой структуре данных не имеет значения. Они удобны для обращения по ключу со сложностью O(1) (т.е. вне зависимости от числа этих пар). Из спецификации: Порядок ключей в Object.keys такой же, как при перечислении через for...in. В описании же for...in сказано in arbitrary order, что значит "в произвольном порядке". Косвенные признаки: В консоли Chrome и во время отладки свойства идут в алфавитном порядке. А при проходе через for...in - в порядке определения. То, что хром так пренебрежительно относится к порядку ключей объекта, говорит о том, что он не имеет никакого значения. В JS нет никаких явных способов изменить порядок полей. Или хотя бы вставить поле в середину объекта.

Ответ 4



var key = function(obj, n) { return obj[Object.keys(obj)[n]]; } key(key(d, 0), 0); Если вы хотите порядок сохранять, то передалайте на массивы: plane: [{ 432: { columns: [{ 543: { name: 'lolo' }, 984: { name: 'lala' }, ... }, ... ] }, ... }, ... ]

пятница, 13 марта 2020 г.

Вывод метода объекта имя которого заданное в переменной [дубликат]

#javascript #json #ооп #объекты


        
             
                
                    
                        
                            На этот вопрос уже дан ответ здесь:
                            
                        
                    
                
                        
                            Как вставить(экранировать) переменную в место перед точкой JS
                                
                                    (1 ответ)
                                
                        
                                Закрыт 4 года назад.
            
                    
Как вывести с объекта foo тот метод, который задан в переменной obl?

var foo = {
   pr: "aaa",
   wr: "bbb",
   bg: "ccc"
};

var obl = 'pr';

document.write(foo.obl);

    


Ответы

Ответ 1



Это называется Bracket Notation(Скобочная нотация) document.write(foo[obl]);

среда, 4 марта 2020 г.

Клонирование объектов Java

#java #ооп #классы #объекты #клонирование


В классе main есть: 
 1) класс сlass1 в котором есть двумерный массив и еще несколько переменных 
 2) функция func(class1 cl) которая принимает объект класса но возвращает другой
тип данных (float), при этом внутри тела функции проводятся манипуляции с двумерным
массивом класса что бы получить ответ

Так вот, проблема в том, что если я создам экземпляр класса, вызову функцию и передам
его туда, то после этого исходный массив объекта меняется (Что мне естественно не нужно) 
Я нашел решение в виде метода clone(), но хеш-код объектов то стал другим, а вот
хеш-код полей внутри клона объекта тот же, и соответственно при изменении массива одного
объекта изменяется массив другого 

Подскажите пожалуйста как решить эту проблему?
    


Ответы

Ответ 1



Сделайте class1 сериализуемым (добавьте implements Serializable в его определение). Сохраняем объекта класса в поток байтов: ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream ous = new ObjectOutputStream(baos); ous.writeObject(new class1()); ous.close(); теперь в func можно передать (class1)new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject() Таким образом объект класса сохраняется в поток из которого восстанавливаться независимый клон.

Ответ 2



Чтобы метод clone клонировал поля объекта, его нужно переопределить в самом классе. По умолчанию он оперирует только примитивными типами и указателями Но Вам нужно просто скопировать массив. Для этого есть метод Arrays.copyOf() или банально вызвать clone для массива Вот тут описаны разные методы получения копии массива https://stackoverflow.com/a/36513254/5376639

среда, 26 февраля 2020 г.

Абстрактные классы, Интерфейсы и наследование

#java #классы #объекты


Почему когда Абстрактный класс имплиментирует(реализовывает) 2-3 интерфейса к примеру,
он не имплиментирует(реализовывает) методы в себя(Абстрактный класс). То есть если
в обычном классе при имплиментации мы обязаны реализовать методы, то в Абстрактном
классе компилятор никак не ругается, что мы не реализовали методы. Пробовал через наследников
абстрактного класса достучаться до этих методов, да всё работает, но не пойму почему
мы их не определяем в абстрактном классе.
    


Ответы

Ответ 1



Интерфейс по идее должен содержать только сигнатуры методов, определяющие возможности того или иного объекта, к сожалению начиная с Java 8, вас могут смущать интерфейсы, содержащие default реализации методов, но не стоит на них обращать внимания, пока не поймёте, что вам это необходимо. Абстрактный класс имеет всё, что имеет обычный класс, однако один или более его методов не содержит реализации, но тем не менее он является почти полноценным. Т.е. он уже достаточно специфичен и описывает только малую часть моделей, однако он всё ещё обобщает некоторые свойства. Типичный пример приводят на животных. Интерфейс Movable может содержать метод move, однако каждое животное двигается по своему, кто-то летает, кто-то плавает. Далее абстрактным классом может выступать птица - Bird, которая будет содержать поле крыло - Wing. А далее мы реализуем конкретную модель цыплёнок - Chicken, который вроде и содержит крыло, однако летать не умеет, поэтому ему требуется реализовать метод move, не использовав поле Wing, а только перемещение по земле. Однако при написании класса сов - Owl, будем реализовывать метод move в виде полёта используя Wing.

Ответ 2



Абстрактным является класс, содержащий один или более абстрактных методов. Такой класс может содержать и обычные методы, наследоваться от другого абстрактного класса, а также имплементировать интерфейсы. Любой класс, который наследуется от абстрактного, обязан реализовать абстрактные методы предка, либо сам быть объявлен абстрактным, оставляя их реализацию потомкам. Полностью свойства интерфейса здесь рассматривать не будем, поясним только то, что касается вопроса. Интерфейс содержит методы без реализации (не считая методов по умолчанию). Имплементировать интерфейсы могут как обычные, так и абстрактные классы. Обычные классы обязаны реализовать методы интерфейса, но абстрактные могут это делать, а могут и нет. interface Iface1{ void method1(); } interface Iface2{ void method2(); } interface Iface3{ void method3(); } abstract class Abs implements Iface1, Iface2, Iface3{ //объявляем собственный абстрактный метод abstract void absMethod(); //объявляем метод интерфейса Iface1, но не реализуем //его здесь (имеем право, но не обязаны!) public abstract void method1(); //реализуем метод из интерфейса Iface2 прямо здесь public void method2(){ System.out.println("I'm method2!"); } /*метод method3 из интерфейса Iface3 мы даже не объявляем и оставляем его для реализации потомкам*/ } class Real extends Abs{ void absMethod(){ System.out.println("I'm a real absMethod!"); } public void method1(){ System.out.println("I'm a real Iface1.method1!"); } public void method3(){ System.out.println("I'm a real Iface3.method3!"); } } class PrimerAbs{ public static void main(String[] args){ Real real = new Real(); real.absMethod(); real.method1(); real.method2(); real.method3(); } } В данном примере объявлены три интерфейса, абстрактный класс, имплементирующий эти интерфейсы и обычный класс, который наследуется от абстрактного. В абстрактном объявлен свой собственный абстрактный метод absMethod(), объявлен метод method1 из интерфейса Iface1, но не реализован, т.к. здесь не обязательно (но можно) это делать, реализован метод method2 из интерфейса Iface2, что возможно, но не обязательно. Метод method3 из интерфейса Iface3 даже не объявлен и предоставлен для решения потомкам. Следует обратить внимание, что в абстрактном классе объявление методов из интерфейса, если они не реализуются в нём, должны быть с модификаторами public и abstract, иначе компилятор начнёт ругаться.

Python Как узнать кому принадлежит объект через метод этого объекта

#python #python_3x #ооп #классы #объекты


Пример: есть объект Персона, у которого есть объект Голова. У Головы есть метод who_my_owner(),
который должен возвращать Персону, кому она принадлежит. Можно, конечно, использовать
уникальные идентификаторы, чтобы при создании головы, ей сообщался ид хозяина. Но есть
ли другой способ, чтобы уместить его в один метод who_my_owner() и без дополнительных
манипуляций с остальным кодом?

class Person:
    def __init__(self):
        self.head = Head()

class Head:
    def who_my_owner(self):
        pass

pers1 = Person()
pers2 = Person()
pers3 = pers1.head.who_my_owner() #должно быть эквивалентно pers3 = pers1

    


Ответы

Ответ 1



class Person: def __init__(self): self.head = Head(self) class Head(): def __init__(self, parent=None): super().__init__() self.parent = parent def who_my_owner(self): # pass return self.parent pers1 = Person() print(f"pers1 - {pers1}") pers2 = Person() pers3 = pers1.head.who_my_owner() #должно быть эквивалентно pers3 = pers1 print(f"pers3 - {pers3}") pers1 - pers3 -

вторник, 25 февраля 2020 г.

Javascript свойства обьектов

#javascript #объекты


Комментариями помечена проблема
var obj = {a:2};
obj.b = 3;
var obj2 = {
  y: obj.b + obj.a,
  d: y //не могу свойству d присвоить значение свойства y
};
//obj2.d = obj2.y; //а вот так могу
console.log(obj2.y);
console.log(obj2.d);

Не могу свойству d объекта obj2 присвоить значение свойства y этого же объекта.    


Ответы

Ответ 1



Смотрите в чем ошибка: 1)this указывает на контекст исполнения, т.е когда вы делаете var obj2={ d:this.y } то, this указывает на объект window. 2) когда пишете так var obj2={ y: 'ололололо', d:y } то в цепочке областей видимости(Scope chain) переменной "y" нет, однако, если вы сделаете так: var y = '2' var obj2={ y: 'ололололо', d:y } то получите свойство "d" со значением 2. Новое звено в цепочке видимости происходит при вступление в новый контекст исполнения... Можете использовать конструктор, тогда this будет указывать на новоявленный объект: function Foo(){ this.x = 'lol', this.y = this.x } b = new Foo(); console.log(b.y)

Ответ 2



оно? var obj = { 'a': 2, 'b': 3 } var obj2 = { y: obj.b + obj.a, get d() { return this.y; }, }; console.log(obj2.y); console.log(obj2.d);

Ответ 3



Оно? var obj={a:2}; obj.b=3; var obj2={ y:obj.b+obj.a, d:function(){return this.y}//не могу значению свойства d присвоить значению свойства y }; console.log(obj2.d());

четверг, 13 февраля 2020 г.

Использование object

#c_sharp #объекты


Есть метод обработки события 

private void BillsPanel_MouseDown(object sender, MouseEventArgs e)
{
    billsPanel.Cursor = Cursors.SizeAll;
    mouse_offset = new Point(-e.X, -e.Y);
}


В дальнейшем мне надо будет использовать тот же метод для другий объектов. Могу ли
я как-то использовать object sender. Чтобы писать sender.Cursor Если да, то каким именно
образом?



UPD: Возникла новая задача. Надо было методы для передвижения элементов - панелей
и формы. С панелями разобрался, а с формой творятся чудеса - она ужасно прыгает помимо
того, что стоит if, в котором координаты не отнимаются.

private void Panel_MouseMove(object sender, MouseEventArgs e)
    {
        var obj = sender as Control;
        if (sender is Form)
            obj = sender as Form;
        else if (sender is Control)
            obj = sender as Control;

        if ((sender is Control) && (e.Button == MouseButtons.Left))
        {
            Point mousePos = MousePosition;
            mousePos.Offset(mouse_offset.X - this.Location.X,
                mouse_offset.Y - this.Location.Y);
            obj.Location = mousePos;
        } else if((sender is Form) && (e.Button == MouseButtons.Left))
        {
            Point mousePos = MousePosition;
            mousePos.Offset(mouse_offset.X, mouse_offset.Y); 
            obj.Location = mousePos;
        }

    


Ответы

Ответ 1



private void BillsPanel_MouseDown(object sender, MouseEventArgs e) { if (sender is Control) { Control control = (Control)sender; control.Cursor = Cursors.SizeAll; } mouse_offset = new Point(-e.X, -e.Y); }

Ответ 2



Приведите ваш объект к нужному типу и используйте: var obj = sender as Panel; "Но есть нюанс" функцию можно будет использовать только для объектов этого типа. Поэтому есть смысл подъняться по "дереву предков" до первого имеющего нужное вам свойство или функцию.

среда, 5 февраля 2020 г.

Определение объектов в C++

#cpp #классы #объекты #стек


Добрый день, интересует такой вопрос, по поводу определения объектов в С++. Насколько
я знаю объекты можно определять, как в стеке так и в куче. Знаю, что в стеке доступ
к объектам будет быстрее, но если нужно будет запрашивать большое количество памяти,
то нужно будет определять его в куче. Это в принципе все, что я знаю об этом. Хотелось
бы услышать внятный ответ, когда и в каких ситуациях предпочтительнее тот или иной способ.
    


Ответы

Ответ 1



Это в принципе все, что я знаю об этом. Хотелось бы услышать внятный ответ, когда и в каких ситуациях предпочтительнее тот или иной способ. Введем для этого пояснения такое понятие, как время жизни объекта (object lifetime). Будем считать, что объект начинает жизнь тогда, когда под него выделилась память и завершилась его инициализация. Всякие отводы, тонкости и закавыки рассматривать не будем. Объект умирает, когда память им занимаемая была освобождена или деструктор (если он есть и не тривиальный) объекта был вызван. Итак, для начала рассмотрим коротенько четыре "времени хранения" (storage duration). Статическое время хранения (static storage duration) - всё статическое живет от момента создания до самого конца программы. Потоковое время хранения (thread storage duration) - всё потоковое живет от момента создания до конца потока в котором создано. Автоматическое время хранения (automatic storage duration) - всё автоматическое живет от момента создания до конца блока в котором оно было создано. Динамическое время хранения (dynamic storage duration) - всё динамическое живет от момента создания до того момента, пока его явно не прихлопнут. Соответственно уже отсюда можно сделать вывод что нам необходимо. A. Если объект должен жить всю программу (ну, почти), то варианта два: Использовать объект с потоковым временем хранения, ежели у нас имеется один, живущий всю программу поток. Использовать объект с статическим временем хранения. Еще вариант, использовать динамический объект, но для его корректного уничтожения придется либо в какой-то из функций его явно уничтожить, что как бы уже подразумевает, что объект живет меньше чем статические объекты, либо же в деструкторе одного из статических объектов уничтожить и наш динамический объект, только вот получается, что нам для этого нужен статический объект, так что такой вариант не рассматриваем. Вариант не уничтожать его совсем - система прихлопнет память, рассматривать не будем, т.к. для объектов не будет вызван деструктор, а мы рассматриваем общее для всех объектов, а не отдельных их "видов". Так что для "чистоты эксперимента" подобные варианты мы не рассматриваем. Также выбросим из повествования временные объекты. B. С потоковыми объектами, практически также, как и со статическими, только в масштабах потока, так что расписывать не буду, ибо и так ясно. C. Если нам нужен объект, который должен быть уничтожен после выхода из блока, в котором создался, то варианта два: Использовать автоматический объект. Использовать динамический объект, но при этом придется вручную его создавать и уничтожать. D. Если нам необходимо, чтобы объект, созданный в блоке жил до самого конца программы (или потока),то вариант у нас один: Сделать его статическим объектом, ну или потоковым, если речь о потоке. С динамическим объектом та же фигня, что и в прошлый раз - до конца такое не доживет, либо уничтожится не правильно (в общем случае). E. Если нам необходимо, чтобы объект жил после выхода из блока в котором создан, но мы не знаем до какого времени он нам понадобится и, жить ему всю программу не нужно, то здесь вариант тоже один: Динамический объект. Теперь по каждому пункту отдельно. A. Потоковый или статический? А смотрим на программу. У нас планируется всего один поток? Если да, то нефиг пытать потоковый класс памяти. Если же потоков может быть несколько, то у каждого потока должна быть своя такая переменная? Если да, то потоковый берем, если нет - статический. B. см. предыдущий пункт. C. Автоматический или динамический? Объекты маленькие, их количество известно и они точно влезут в стек (без фанатизма)? Если да то использовать автоматические объекты или динамические зависит от хотелок разработчика и здравого смысла. Если не нужна динамика, то нафиг заниматься ручной работой? Но если очень хочется, то можно хоть каждый int делать динамическим. Если же объекты тяжелые и не хочется на них тратить стек, или же нам неизвестно конечное количество одновременно живущих элементов, то тут только динамические объекты прокатят. Вариант "создам здоровый массив на все случаи жизни" здесь не прокатит, т.к. выше оговорено, что конечное количество одновременно живущих объектов неизвестно и, соответственно, оно всегда будет равно sizeof(mySuperArray)/sizeof(*mySuperArray) + 1. D. Всё как и прежде - смотрим на потребности в каждом потоке. E. Без вариантов. В программах, чаще всего, встречается смесь из всего высказанного выше в разных пропорциях и сочетаниях. Вот такая абсолютно бесполезная портянка, т.к. она всё равно не покрывает всего и вся и не является истиной в последней инстанции.

Ответ 2



Стек ограничен, и время жизни автоматических объектов заканчивается, когда выполнение выходит из блока, где объект был объявлен. Поэтому, когда требуется контролировать время жизни и иметь "неограниченный" размер данных, приходится использовать кучу. Доступ быстрее в стеке не будет, так как память физически та же самая, что и для объектов в куче. Другое дело, что данные могут быть в кэше, где скорость доступа выше, но это характерно для любых данных, независимо от места их объявления. В давние времена пытались оптимизировать добавляя ключевое слово register к объявляемой переменной. Сейчас это уже не актуально. Более того, начиная с c++17 это слово зарезервировано и не используется.

Ответ 3



Таки да (!), доступ к объектам в куче будет медленнее. Так как в случае создания объектов в куче еще добавляется время, необходимое для выделение и освобождение памяти в куче. Если объект в программе один и создается этот объект один раз, то различие невелико. А если в куче приходится во время работы создавать и удалять МНОГО объектов, то время на выделение объекта в куче становится существенным (по сравнению с временем на выделение объекта в стеке). В стеке память под объекты в большинстве современных архитектур выделяются одной машинной командой. А чтобы выделить память под объекты в куче, надо выполнить целую подпрограмму. UPD1: так а почему именно доступ(!) будет медленнее? Я бы понял создание/удаление объекта. Но доступ то... Если надо в программе ПОСТОЯННО создавать и удалять объекты, то время ДОСТУПА включает и время на создание/удаление объекта. ИБО очевидно, что не создав объект, доступа к нему не получишь. Собственно же ДОСТУП, конечно, в СОВРЕМЕННЫХ архитектурах персоналок и мобильников не отличается по времени. Однако были и есть архитектуры (например приснопамятная однокристалка от Интел пятьдесят первой серии) в которых даже и собственно ДОСТУП к памяти значительно отличается по времени от ДОСТУПА к стеку. UPD2: Опа-на. Пока я отвечал, комментарий на который я отвечал куда-то делся. :-) Чудны дела Твои Господи. :-)

понедельник, 3 февраля 2020 г.

Методы equals и hashcode

#java #объекты


    BlackBox object1 = new BlackBox(5, 10);
    BlackBox object2 = new BlackBox(5, 10);


    System.out.println(object1.hashCode());
    System.out.println(object2.hashCode());
    System.out.println(object1.equals(object2));

1956725890
356573597
false


Из статьи на хабре: если объекты одинаковые, то и хеш-коды одинаковые (но не наоборот,
см. правило 3)

Почему в вышеприведенном примере хеш-коды разные? Почему equals() возвращает false?
    


Ответы

Ответ 1



если объекты одинаковые, то и хеш-коды одинаковые Это правильное утверждение, только трактуете вы его неверно. Это ваша задача как программиста сделать так, чтобы хешкоды у одинаковых объектов были одинаковы (меру одинаковости выбираете и контролируете вы). Так как нельзя заранее определить, какие объекты будут равны, по умолчанию хешкодом является, емнип, указатель на объект, и в этом случае объект будет равен только себе самому. Чтобы изменить это поведение, вам нужно переопределить методы .hashcode() и .equals().

Ответ 2



Если вы хотите сравнивать объекты собственного класса вам необходимо переопределить свойство equal() в вашем классе.

Ответ 3



Загляните под капот. Советую прочитать Рихтер CLR via C# стр. 172. Ссылки и будут разными, так как это два разных объекта. BlackBox object1 = new BlackBox(5, 10); BlackBox object2 = object1; System.out.println(object1.hashCode()); System.out.println(object2.hashCode()); System.out.println(object1.equals(object2));

воскресенье, 2 февраля 2020 г.

Как достать строку из массива который является значением ключа объекта?

#javascript #массивы #циклы #объекты




// Программа поиска операторов мобильной связи Украины
"use strict";
// Создаем объект с значениями ключей-массивами(коды операторов) 
var mobile = {
  Kyivstar: ["039", "067", "068", "096", "097", "098"],
  Vodafone: ["050", "066", "095", "099"],
  Lifecell: ["063", "093"],
  Intertelecom: ["094"],
  PEOPLEnet: ["092"],
  TriMob: ["091"]
}
// Запрашиваем у пользователя номер мобильного телефона
var user = prompt("Введите номер мобильного телефона в формате: 000 1112233", "");
// Получаем доступ к первым 3-м индексам user
var x = user.substr(0, 3);
// Прогоняем в цикле все ключи
for (var key in mobile) {
  var arr = mobile[key];
  // Проходимся по всем массивам
  var check = arr.forEach(function (item, i, arr) {
    if (x === item) {
      //Выводим пользователю результат
      alert("Вас приветствует " + key);
    } 
  }); 
}




Задача была такая:  

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

Я не совсем уверен в правильности решения данной задачи.
Вроде все работает, а правильно ли?
    


Ответы

Ответ 1



Вставил из старой проверки своей с сайта, может пригодится: // Создаем объект с значениями ключей-массивами(коды операторов) var mobile = { Kyivstar: ["039", "067", "068", "096", "097", "098"], Vodafone: ["050", "066", "095", "099"], Lifecell: ["063", "093"], Intertelecom: ["094"], PEOPLEnet: ["092"], TriMob: ["091"] } // Запрашиваем у пользователя номер мобильного телефона var user = prompt("Введите номер мобильного телефона", ""); var x; var y = -1; user = getTelNums(user); switch (user.length) { case 10: y = 0; break; case 11: y = 1; break; default: alert('неверный формат'); break; } if (y >= 0) { // Получаем доступ к первым 3-м индексам user var x = user.substr(y, 3); // Прогоняем в цикле все ключи var op = "Неизвестный оператор"; for (var key in mobile) { var arr = mobile[key]; // Проходимся по всем массивам var check = arr.forEach(function(item, i, arr) { if (x === item) { op = key; return; } }); } //Выводим пользователю результат alert('Вас приветствует '+op); } function getTelNums(telStr) { var regexpNums = /\d/g; var regexpTel = /^([7|8]{0,1}0\d{2})?\d{7}$/; var resultTel = ""; var checkNums = telStr.match(regexpNums); // из строки пользователя получаем массив цифр if (checkNums) { // если массив не пустой // сделаем из него строку: for (var j = 0; j < checkNums.length; j++) resultTel += checkNums[j]; // проверим, телефон ли это: if (!regexpTel.test(resultTel)) { resultTel = ""; } } return resultTel; }

суббота, 1 февраля 2020 г.

Как перевести массив в многоуровневый объект (javascript)

#javascript #массивы #объекты


Есть массив:

var authority = [
    "Дзержинським",
    "РВ",
    "у",
    "місті",
    "Харкові",
    "ГУ",
    "ДМС",
    "України",
    "в",
    "Харківській",
    "області"
]


Необходимо на его основе получить многоуровневый объект вида:

var obj = {
    "Дзержинським": {
        "РВ": {
            "у": {
                "місті": {
                    "Харкові": {
                        "ГУ": {
                            "ДМС": {
                                "України": {
                                    "в": {
                                        "Харківській": {
                                            "області": {

                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
};


Массив может быть разной длины, следовательно объект может иметь больший/меньший
уровень вложенностей.

Подскажите пожалуйста, как это сделать при помощи цикла? Или возможно есть более
правильное решение данной задачи?

Кроме такого больше ничего в голову не приходит :(

var tempObj = {};

tempObj[authority[0]] = {};
tempObj[authority[0]][authority[1]] = {};
tempObj[authority[0]][authority[1]][authority[2]] = {};
tempObj[authority[0]][authority[1]][authority[2]][authority[3]] = {};
tempObj[authority[0]][authority[1]][authority[2]][authority[3]][authority[4]] = {};
tempObj[authority[0]][authority[1]][authority[2]][authority[3]][authority[4]][authority[5]]
= {};
...


    


Ответы

Ответ 1



Вам поможет reduceRight, заворачиваем каждую итерацию аккумулятор в свойство нового объекта под именем элемента массива. var authority = [ "Дзержинським","РВ","у","місті","Харкові", "ГУ", "ДМС","України","в","Харківській","області"]; let result = authority.reduceRight((acc, el) => ({[el]: acc}), {}); console.log(result); —- upd сокращенная форма записи лямбды в сниппете эквивалентна функции reduceRight : authority.reduceRight(reduceFunc, {}); function reduceFunc(accumulator, element) { var newAccumulator = {}; newAccumulator[element] = accumulator; return newAccumulator; }

Ответ 2



var a = ["Дзержинським", "РВ", "у", "місті", "Харкові", "ГУ", "ДМС", "України", "в", "Харківській", "області"] var res = {}, x = res for (var key of a) x = x[key] = {} console.log(res) .as-console-wrapper.as-console-wrapper { max-height: 100vh }

среда, 29 января 2020 г.

Удалить похожие объекты?

#php #массивы #объекты


Массив:
$objects = array(
    (object)array('name'=>'Stiven','age'=>25,'variant'=>(object)array('surname'=>'Sigal')),
    (object)array('name'=>'Michael','age'=>30,'variant'=>(object)array('surname'=>'Jackson')),
    (object)array('name'=>'Brad','age'=>35,'variant'=>(object)array('surname'=>'Pit')),
    (object)array('name'=>'Jolie','age'=>35,'variant'=>(object)array('surname'=>'Pit')),
);
echo "
";
print_r($objects);

Как удалить объекты, которые имеют одинаковые variant->surname и age? Точнее не удалить,
а оставить один из них, т.е. чтобы таких одинаковых элементов не было в массиве.    


Ответы

Ответ 1



отсортировать с помощью ф-ии usort() и собственной ф-ии, сравнивающей по полям variant->surname и age. Тогда объекты с одинаковыми значениями точно будут подряд; пробежаться array_filter() и ф-ей, сохраняющей статически предыдущие значения variant->surname и age, с тем, чтобы вернуть true только, если значения изменились. Upd. для ленивых: работающий пример.

Ответ 2



тупо перебором: бежим по массиву, если элемент первый, то копируем элемент проверяем наличие элемента в новом массиве если нет, копируем элемент и бежим дальше если да, то просто бежим дальше в заключение делаем unset() исходного массива, если он не нужен В результате будем иметь массив без дублей

Ответ 3



array_unique(),array_walk(), array_map(), array_filter()

Ответ 4



Прошу прощение за некропост(нашёл его через гугл) Мой вариант решения той же проблемы: /** * Вернёт только те объекты из массива $bad, которые уникальны по признаку $property * @param array $bad * @param string $property */ function array_object_unique($bad,$property) { foreach ($bad as $k1 => $a) { foreach ($good as $k2 => $g) { if ($a->$property == $g->$property) { continue(2); } } $good[] = $a; } return $good; } Хотя вариант ув. @sergiks тоже хороший, запустить его в контексте класса не удалось. P.s. Между прочим этот же алгоритм предложил ув.@akalend

Ответ 5



Пришел к такому решению: $tmp = array(); foreach ($objects as $item=>$object) { $tmp[$object->variant->surname][$object->age] = $object; } print_r($tmp); Все бы хорошо, да вот только как это переделать в прежний массив пока не знаю. (думаюю...) Если у кого есть идеи, плыз хелп.

Утилитарные классы - добро или зло?

#java #ооп #классы #объекты #static


Есть вот такой спорный вопрос.

Многие используют утилитарные классы, которые состоят из статических методов. Это
всего функции со входом и результатом. Такие используют и библиотеки Java, например,
Math. Многие делают свои классы типа Utils, которые содержат в себе набор используемых
в разных местах инструментов. Я не вижу минусов, с точки зрения SOLID:
S класс создан для общей по смыслу задачи
O да
L неприменимо. Обычно не используется наследование.
I неприменимо. Нет интерефейса
D да. 
Также они отвечают принципу KISS, и легко модульно тестируются при желании. На методы
также можно ссылаться для функционального подхода (напр., Function delCommentsConverter
= QueryUtils::deleteComments). Ну в общем, полноценные роботяги.

Но также есть мнение, что это неверные подход, не по ООП, а Java это ОО-язык. Что
это не класс, и вызов методов напрямую - это очень плохо. Типа нужно сначала получить
инстанс, и только тогда работать с ним. Я не вижу в этом преимуществ, наоборот - растёт
код, неудобно пользоваться.

А как вы думаете?
    


Ответы

Ответ 1



Имхо, статические методы должны: 1) делать очень маленькую специфичную работу; 2) не должны напрямую относиться к бизнес-логике; 3) как следствие 1) и 2) — их не надо мокать; 4) их можно тестировать отдельно. Давайте рассмотрим каждый пункт отдельно. Делать очень маленькую специфичную работу Я имею ввиду, что в статическом методе-помощнике должно быть минимум логики, которая относится только к той одной конкретной операции, для которой метод предназначен. Например, как вы думаете, сколько логики в методe типа Math.min? Также такие методы должны быть чистыми. То есть при одинаковых входных данных они должны возвращать один и тот же результат и они не должны иметь состояния. (Но тут есть исключения, связанные со временем. Например, получение текущего времени в разные моменты будет возвращать разный результат). Не должны напрямую относиться к бизнес-логике Ваша бизнес-логика должна обладать гибкостью. Например, сегодня вы используете один калькулятор зарплат, а завтра — другой. По идее, это должно достигаться просто подменой одной реализации калькулятора другой. Отсутсвие O и L из SOLID по сути связывает статические методы, вы не можете подложить другую реализацию статического метода в рантайме, если только этот статический метод не нарушает предыдущий пункт. Поэтому, если вам надо сделать что-то, что не относится напрямую к бизнес логике и никогда не планируется измениться (например, округлить число, сортировать массив, возвести число в степень, посчитать расстояние между точками, распарсить дату их строки) — вы смело можете писать статические методы. Но если вам надо реализовать бизнес-логику (найти победителя в игре, посчитать налоговую декларацию, обновить значение поля А в зависимости от значения поля Б на форме, отправить сообщение юзеру при возникновении какого-либо события) — то эта логика должна быть максимально гибкой, основные её части должны быть заменяемы, там где надо даже в райтейме — то есть вы не можете делать её на статических методах. Как следствие 1) и 2) — их не надо мокать При тестировании логики, которая использует ваши статические методы, нет никакого смысла их мокать (опять же, если речь идет не о получении текущей даты/времени), так как эти методы к логике не относятся, никогда не получат альтернативной реализации и всегда на один и тот же запрос вернут один и тот же ответ. Вам никогда не понадобится имитация того, что строка "10" была распарсена в 15 или 20. "10" всегда при парсинге будет 10. Их можно тестировать отдельно Тут, по идее, очевидно, если вы следовали предыдущим советам, то у вас ваши статические методы — небольшие, не будут меняться, не имеют состояния и не относятся напрямую к бизнес-логике. В этом случае для тестирования этих методов вам не надо тянуть классы бизнес-логики или мокать их как-либо: вы можете спокойно тестировать эти методы без привязки к логике приложения. Ещё немножко текста в похожем вопросе

Ответ 2



Конечно, статические методы не являются объектно-ориентированным решением, тут апологеты ООП правы. Однако, есть вопросы к самой объектной парадигме. Она идеально подходит для решения одних задач, и совершенно не подходит для других. Собственно, любая парадигма имеет границы применимости. Именно поэтому концепция всё есть объект обрастает многочисленными но. Пример: в DDD разделяют сущности (entities) и службы (services). Службы предназначены для описания процессов, и они не обладают состоянием. С точки зрения «правильного» ООП объекты без состояния — это нонсенс. Но с практической точки зрения в предметной области есть бизнес-процессы. Это последовательности операций, и никакого состояния они не предусматривают. Поэтому в реальных программах чистые концепции дополняются деталями. Более того, выразительность языков программирования связана с тем, как они позволяют выражать нюансы. Возвращаемся к статическим методам и утилитарным классам. В Java и C# они существуют потому, что это простой способ выразить концепцию функции. Можно спорить о том, делать ли sin функцией класса Double или нет, но в классической математике sin это не метод действительного числа, а функция, которая умеет работать с действительным числом. Статические методы позволяют выразить эту концепцию и упростить код. Однако, есть несколько проблем, связанных с тестированием. Вы можете протестировать функции независимо, но если ваш код вызывает статический метод, вы не можете вставить вместо него заглушку. Решения этой проблемы могут быть разными. Например, вместо прямого вызова DateTime.Now в C# можно предусмотреть класс TimeProvider с виртуальным методом Now(). Можно передавать ссылку на функцию. В конце концов, можно не тестировать вызов функций sin или sqrt, а проверять, что результат вычислений попадает в ожидаемый диапазон. Есть также паттерн Окружающий контекст (Ambient context), который позволяет сочетать выразительность статических методов с возможностью подменить реализацию заглушкой. В целом, в практических целях использование статических методов вполне оправдано.

вторник, 28 января 2020 г.

Аналог push() для объектов

#массивы #javascript #объекты #функции


Всем привет. Сегодня столкнулся с такой проблемой. Мне понадобилось добавлять элементы
в ассоциативный массив. На JavaScript нет ассоциативных массивов ,поэтому я сделал
как объект. Теперь не могу найти аналог функции push(). Подскажите, если кто-нибудь
знает. Спасибо.    


Ответы

Ответ 1



вы хотите, чтобы ключами были обычные инкрементирующиеся числа? Не совсем. Первый ключ - какое-то слово, второй ключ - числа. obj['key'] = []; obj['key'].push('value1'); obj['key'].push('value2'); obj['key'][0];// 'value1' obj['key'][1];// 'value2'

Ответ 2



Через цикл не сложно заполнить объект по типу ключ - значение из массива. var dataRow = ['string1', 'string2', 'string1']; var obj = {}; $(dataRow).each(function(e, i){ obj[e] = i; }); // e - индекс ячейки в массиве. // i - содержание ячейки, там может быть что угодно. На выходе получим: Object {0: "string1", 1: "string2", 2: "string1"} Или можно так: var dataRow = [{name: 'John', data: "text1"}, {name: 'Mark', data: "text2"}, {name: 'Tom', data: "text3"}]; var obj = {}; $(dataRow).each(function(e, i){ obj[i.name] = i.data; }); На выходе будет: Object {John: "text1", Mark: "text2", Tom: "text3"}

Какая разница между объявлением класса через function и через class?

#javascript #классы #объекты


Зачем нужно это:

function createClass() 
{
    this.name = "oneOfMyClasses";
}

var obj = new createClass();


Если есть это:

class myClass 
{
    constructor() 
    {
        this.name = "oneOfMyClasses";
    }
}

var obj = new myClass();


Какая разница между объявлением класса через function и через class?
    


Ответы

Ответ 1



На самом деле классы — это "специальные функции", поэтому точно также, как вы определяете функции, вы можете определять и классы. В JavaScript есть отдельные термины для таких объявлений: class declaration function declaration Разница между объявлением функции (function declaration) и объявлением класса (class declaration) в том, что объявление функции совершает подъём (hoisted), в то время как объявление класса — нет. Поэтому вначале необходимо объявить ваш класс и только затем работать с ним. (Источник: Classes) Поднятие задумывалось как общий способ мышления о том, как контекст исполнения (в частности, фазы создания и исполнения) работает в JavaScript. Однако, hoisting может привести и к недоразумениям. Например, hoisting учит, что объявление переменной или функции физически перемещается в начало вашего кода, хотя в действительности этого не происходит. На самом же деле, объявления переменных и функций попадают в память в процессе фазы компиляции, но остаются в коде на том месте, где вы их объявили. Поднятие (hoisted) constructor - специальный метод, служащий для создания и инициализации объектов, созданных с использованием class. Любая функция, вызванная через new становится конструктором и позволяет создать один объект. Также будет полезно почитать: constructor new

Ответ 2



// это было function createClass() { ... // когда этого еще не было class myClass { ...

Ответ 3



Классы - это по сути синтаксический сахар в ES6. Под капотом все равно все происходит, как будто: function createClass() {

Java. Почему нельзя изменить ссылку на объект в методе?

#java #ссылки #объекты #теория #параметры


Мой педагог задал мне задание ответить на ряд вопросов. И два их них меня сильно
смущают. 


  
  Почему нельзя изменить ссылку на объект в методе?
  


Не могу понять смысл вопроса(((


  
  Как в Java передаются параметры в методы?
  


Я гуглил этот вопрос и понял что по всегда по значению но что точно это значит не понял.

Не могли бы вы мне помочь разобраться в этой ситуации.
    


Ответы

Ответ 1



Почему нельзя изменить ссылку на объект в методе? Потому что в метод передается не ссылка, а объект, который содержит копию ссылки. Как в Java передаются параметры в методы? Все аргументы (как примитивные типы, так и объекты) в Java передаются при вызове по значению. Тут сразу стоит оговориться, что объект по сути представляет ссылку, следовательно, при изменении объекта в методе, изменится и исходный объект. Подробнее можно почитать в «Подробное рассмотрение особенностей передачи аргументов» в полном руководстве по Java авторства Герберта Шилдта.

Ответ 2



Как намекнул Vlad from Moscow в комментарии к вопросу, вопрос довольно странный, и на мой взгляд он не вполне корректен -- либо ваш преподаватель не очень хорошо умеет выражать свои мысли, либо вы как-то слегка исказили его вопрос. Дело в том, что в методе менять ссылку вообще-то можно. Строго говоря, в Jave обычно говорят не о ссылках на объект, а о переменных (полях, аргументах) объектного типа. Но фактически значением таких переменных являются ссылки на объекты. Методы в качестве своих аргументов получают копии этих ссылок и могут делать с ними что хотят (т. е. присваивать им значения ссылок на другие объекты или null - "пустую ссылку"), что никак не отражается на значениях переменных, которые были переданы методу при его вызове. Так что вот такой код public class TestQQ { static void qq(String s) { System.out.println(s); s = "Что-то новое..."; // Это ссылка или не ссылка меняется ? System.out.println(s); } public static void main(String[] args) { String string = "Нельзя менять ссылки?"; qq(string); System.out.println(string); } } Создает новый объект класса String со значением "Нельзя менять ссылки?"; Присваивает ссылку на него переменной string; Вызывает метод qq() и передает ему копию переменной string (т. е. создает вторую ссылку на ту же строку "Нельзя менять ссылки?") Метод qq() выводит на консоль содержимое того объекта, ссылка на который содержится в его параметре - т. е. то же самое "нельзя?"; Метод qq() своему параметру s присваивает новое значение - ссылку на новую строку "Что-то новое...", -- вторая ссылка на "нельзя" исчезает, но исходная переменная string в главной программе при этом никак не меняется и по-прежнему содержит ссылку на то же самое изначальное "нельзя?"; Метод qq() печатает новую строку ("Что-то новое...") и возвращает управление в главную программу (метод main); Метод main() печатает содержимое объекта, который содержится (т. е. ссылка на который содержится) в переменной string - это по-прежнему изначальная строка "Нельзя менять ссылки?" Вывод будет такой:Нельзя менять ссылки? Что-то новое Нельзя менять ссылки? Но при этом надо отчетливо понимать, что хотя метод не может изменить значение объектной переменной, переданной ему в качестве параметра (т. е. ссылку на объект), он за милую душу может изменить сам объект! Например, в такой программе import java.util.ArrayList; public class TestQQQ { static void qqq(ArrayList list) { list.add("можно."); } public static void main(String[] args) { ArrayList strings = new ArrayList(); strings.add("А объекты менять...?"); qqq(strings); System.out.println(strings); } } метод qqq() добавляет в список, ссылку на который он получил, новую строку "можно.", и в результате мы получаем на выходе вот что: [А объекты менять...?, можно.]

Ответ 3



Почему нельзя изменить ссылку на объект в методе? При передаче объекта в метод происходит просто копирование ссылки на него (Никаких копий объекта не создаётся при передачи!). И уже с помощью неё вы общаетесь с исходным объектом. Отсюда должно быть понятно, почему при перезаписывании в эту ссылку нового объекта старый не меняется. Простой пример для разъяснения: List list1 = new ArrayList<>(); //Создаём объект и кладём в ссылку List list2 = list1; //Просто копируем ссылку list2.add(new Object); //Через копию ссылки мы меняем исходный объект в list1 list2 = new ArrayList<>(); //Хоть мы и переписали в ссылку новый объект, //исходный никуда не делся, он всё также лежит в list1. Как в Java передаются параметры в методы? Примитивы по значению, объекты - как я описал выше (не знаю как правильно называется этот способ). Update: спасибо @Roman, правильное название способа передачи объектов в метод - вызов по соиспользованию (call by sharing)

Преобразовать object[] в string[]

#c_sharp #массивы #строки #объекты


Собственно вопрос в шапке.

Есть некий массив object[] состоящий из Guid'ников, нужно этот массив преобразовать
в string[]. 

Пробовал так:

var strings = objects as string[];


Но получил null.

Есть какой-то способ избежать цикла и скастить всё это сразу?
    


Ответы

Ответ 1



Метод: Array.ConvertAll - преобразует массив одного типа в массив другого типа. Вариант #1 object[] inputArray = new object[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; string[] resultArray = Array.ConvertAll(inputArray, x => x?.ToString() ?? string.Empty); Ссылка на источник: Converting a Object[] array to an string[] array in C# (ConvertAll method) Вариант #2 string ConvertObjectToString(object obj) { return obj?.ToString() ?? string.Empty; } object[] input = new object[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; string[] result = Array.ConvertAll(input, ConvertObjectToString); Ссылка на источник: Converting a Object[] array to an string[] array in C# (Array.ConvertAll Method)

Ответ 2



var strings = objects.Select(x => x?.ToString()).ToArray();

Ответ 3



Вариант №1 var objects = new Object[3] { Guid.NewGuid().ToString("D"), Guid.NewGuid().ToString("D"), Guid.NewGuid().ToString("D") }; var strings = objects.Cast(); Вариант №2 var MyObjects = new Object[3] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; var MyStrings = MyObjects.Cast(); public static IEnumerable Cast(this IEnumerable source) { return source.CastIterator(); } public static IEnumerable CastIterator(this IEnumerable source) { return source.ExpressionToFunc(); } public static IEnumerable ExpressionToFunc(this IEnumerable source) { foreach (var obj in source) { var exp = Expression.Constant(obj.ToString()); var type = Expression.TypeAs(exp, typeof(TResult)); var compile = Expression.Lambda>(type).Compile(); yield return compile(); } }

четверг, 23 января 2020 г.

Объединение объектов в массиве по ключу

#javascript #объекты #объединение #lodash


У меня имеется массив с разными данными , который выглядит примерно так:

[ {
   "_id": "556c978be20c7cd0087c6f10",
   "username": "ivan",
   "music": [
     "Metallica"
   ]
  },
  {
   "_id": "556c978be20c7cd0087c6f10",
   "username": "ivan",
   "interests": [
     "Music",
     "Djent"
   ]
  }, 
  {
   "_id": "556c978be20c7cd0087c6f13",
   "username": "alina",
   "interests": [
     "Music",
     "Literature"
   ]
  },
  {
   "_id": "556c978be20c7cd0087c6f13",
   "username": "alina",
   "music": [
     "Skyharbor"         
   ]
  }
]


Как с объединить объекты в массиве по ключам ('_id') следующим образом (приоритет
lodash):   

[ {
   "_id": "556c978be20c7cd0087c6f10",
   "username": "ivan",
   "music": [
     "Metallica"
   ],
   "interests": [
     "Music",
     "Djent"
   ]
  },
  {
   "_id": "556c978be20c7cd0087c6f13",
   "username": "alina",
   "music": [
     "Skyharbor"         
   ]
   "interests": [
     "Music",
     "Literature"
   ]
  }
]

    


Ответы

Ответ 1



Сгруппировать по идентификаторам можно с помощью groupBy, а затем объединить пары с помощью merge: var users = [{ "_id": "556c978be20c7cd0087c6f10", "username": "ivan", "music": [ "Metallica" ] }, { "_id": "556c978be20c7cd0087c6f10", "username": "ivan", "interests": [ "Music", "Djent" ] }, { "_id": "556c978be20c7cd0087c6f13", "username": "alina", "interests": [ "Music", "Literature" ] }, { "_id": "556c978be20c7cd0087c6f13", "username": "alina", "music": [ "Skyharbor" ] }]; console.log( _.map( _.groupBy( users, function (u) { return u._id } ), function (g) { return _.merge.apply(this, g) } ) ); P. S. Прошу ногами не бить, в первый раз в жизни вижу lodash.

среда, 22 января 2020 г.

Выборка объектов массива с их последующей вставкой в разметку страницы

#javascript #массивы #веб_программирование #циклы #объекты


Господа, прошу помощи, ибо никак не могу организовать логику скрипта, который находил
бы нужные объекты и вставлял их в разметку. Подробности ниже.

Есть таблица календаря, которая генерится а js, есть массив объектов, каждый объект
хранит в себе информацию о годе+месяце (year), дне месяца (day), событии (event), остальные
параметры не так важны. Нужен скрипт, который будет пробегать по массиву, сверять месяц+год
календаря с месяцем+годом в объектах, если все совпадает, то далее пробегать по таблице
и сверять день календаря с днями в объектах, если совпадает, то в ячейку с совпадающей
датой добавлять div с event, хранящимся в объекте.

Сейчас происходит почти то что нужно, НО если в массиве есть несколько объектов с
совпадающими day объекта и днем календаря, то в ячейку с датой добавляется ТОЛЬКО первый
объект, остальные игнорируются.

Вот так это выглядит сейчас:



let arr = [{
    dateEvent: "Первый тест",
    day: "11",
    description: "Первый тест",
    event: "Первый тест",
    names: "Первый тест",
    year: "Октябрь 2017"
  },
  {
    dateEvent: "Второй тест",
    day: "11",
    description: "Первый тест",
    event: "Первый тест",
    names: "Первый тест",
    year: "Октябрь 2017"
  },
  {
    dateEvent: "Третий тест",
    day: "11",
    description: "Первый тест",
    event: "Первый тест",
    names: "Первый тест",
    year: "Октябрь 2017"
  },
  {
    dateEvent: "Четвертый тест",
    day: "10",
    description: "Первый тест",
    event: "Первый тест",
    names: "Первый тест",
    year: "Октябрь 2017"
  },

]

const showAllEvents = () => {

  let arrEvents = arr,
    list = document.getElementById("organizer").getElementsByTagName('td');

  //берем первый день - внешний цикл
  for (let j = 0; j < list.length; j++) {

    //первый объект в массиве - внутренний цикл
    for (let i = 0; i < arrEvents.length; i++) {


      //проверяем соответсвие месяца и года с данными в объекте
      if (document.getElementById('year').innerHTML === arrEvents[i].year) {

        //проверяем день календаря и день объекта
        if (list[j].innerHTML === arrEvents[i].day) {

          //тут слайсится Событие
          let text = arrEvents[i].event,
            slicedEvent = text.slice(0, 15);

          if (slicedEvent.length < text.length) {

            slicedEvent += '...';
          }

          //создаем див, в него вставляем дивы с данными, которые должны хранится
в ячейке
          let appendDiv = document.createElement('div');
          appendDiv.className = 'event-div';

          appendDiv.innerHTML = `
                    
` + slicedEvent + `
`; //вставляем этот див в текущую ячейку document.getElementsByTagName('td')[j].appendChild(appendDiv); } //как я понимаю, внутренний цикл должен повториться и перейти ко второму объекту, //но почему-то вместо этого сразу начинается новая итерация внешнего цикла } } } }; showAllEvents(); body { width: 100%; height: 100%; margin: 0; padding: 0; position: relative; z-index: 333; } #calendar { width: 80%; height: 90%; margin: 0 auto; } #control-month span:first-child, #control-month span:last-child { cursor: pointer; } #control-month div { cursor: pointer; } #organizer { border-collapse: collapse; width: 100%; font-family: monospace; line-height: 1.2em; font-size: 15px; text-align: center; word-break: break-all; table-layout: fixed; } #organizer thead { color: rgb(50, 50, 50); font-size: 10px; } #organizer tbody tr { height: 80px; } #organizer tbody td { position: relative; color: rgb(44, 86, 122); font-size: 10px; vertical-align: top; cursor: pointer; border: 1px solid dimgrey; z-index: 33; } #organizer tbody td:nth-child(n+6), #organizer .holiday { color: rgb(231, 140, 92); } #organizer tbody td.today { background: rgb(220, 0, 0); color: #fff; } #cover-div { width: 15%; height: 25%; position: absolute; background: lightsteelblue; border: 1px solid darkgray; } #cover-div input, #cover-div textarea { box-sizing: border-box; } #overlay-div { width: 100%; height: 100%; top: 0; left: 0; position: fixed; } Title
Октябрь 2017
Сегодня
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Прошу сильно ссаными тряпками не кидаться, а объяснить что происходит, кажется я не совсем верно понимаю работу циклов. Или же в логике ошибка?


Ответы

Ответ 1



Проблема в том, что вы сравниваете list[j].innerHTML === arrEvents[i].day. После первого успешного совпадения list[j].innerHTML уже не будет только текст 11, потому что вы добавляете туда несколько новых элементов document.getElementsByTagName('td')[j].appendChild(appendDiv);. Для обхода этой ситуации можно хранить данные в data-* атрибутах элемента. Вообще, лучше данные хранить там, и по возможности стараться избегать сравнений вида list[j].innerHTML === arrEvents[i].day. Пример работающего кода. let arr = [{ dateEvent: "Первый тест", day: "11", description: "Первый тест", event: "Первый тест", names: "Первый тест", year: "Октябрь 2017" }, { dateEvent: "Второй тест", day: "11", description: "Первый тест", event: "Второй тест", names: "Первый тест", year: "Октябрь 2017" }, { dateEvent: "Третий тест", day: "11", description: "Первый тест", event: "Третий тест", names: "Первый тест", year: "Октябрь 2017" }, { dateEvent: "Четвертый тест", day: "10", description: "Первый тест", event: "Четвертый тест", names: "Первый тест", year: "Октябрь 2017" }, ] const showAllEvents = () => { let arrEvents = arr, list = document.getElementById("organizer").getElementsByTagName('td'), year = document.getElementById('year'); //берем первый день - внешний цикл for (let j = 0; j < list.length; j++) { let td = list[j]; //первый объект в массиве - внутренний цикл for (let i = 0; i < arrEvents.length; i++) { let event = arrEvents[i]; //проверяем соответсвие месяца и года с данными в объекте if (year.innerHTML === event.year) { //проверяем день календаря и день объекта if (td.getAttribute("data-day") === event.day) { //тут слайсится Событие let text = event.event, slicedEvent = text.slice(0, 15); if (slicedEvent.length < text.length) { slicedEvent += '...'; } //создаем див, в него вставляем дивы с данными, которые должны хранится в ячейке let appendDiv = document.createElement('div'); appendDiv.className = 'event-div'; appendDiv.innerHTML = `
` + slicedEvent + `
`; //вставляем этот див в текущую ячейку //document.getElementsByTagName('td')[j].appendChild(appendDiv); td.appendChild(appendDiv); // эквивалетно } //как я понимаю, внутренний цикл должен повториться и перейти ко второму объекту, //но почему-то вместо этого сразу начинается новая итерация внешнего цикла } } } }; showAllEvents(); body { width: 100%; height: 100%; margin: 0; padding: 0; position: relative; z-index: 333; } #calendar { width: 80%; height: 90%; margin: 0 auto; } #control-month span:first-child, #control-month span:last-child { cursor: pointer; } #control-month div { cursor: pointer; } #organizer { border-collapse: collapse; width: 100%; font-family: monospace; line-height: 1.2em; font-size: 15px; text-align: center; word-break: break-all; table-layout: fixed; } #organizer thead { color: rgb(50, 50, 50); font-size: 10px; } #organizer tbody tr { height: 80px; } #organizer tbody td { position: relative; color: rgb(44, 86, 122); font-size: 10px; vertical-align: top; cursor: pointer; border: 1px solid dimgrey; z-index: 33; } #organizer tbody td:nth-child(n+6), #organizer .holiday { color: rgb(231, 140, 92); } #organizer tbody td.today { background: rgb(220, 0, 0); color: #fff; } #cover-div { width: 15%; height: 25%; position: absolute; background: lightsteelblue; border: 1px solid darkgray; } #cover-div input, #cover-div textarea { box-sizing: border-box; } #overlay-div { width: 100%; height: 100%; top: 0; left: 0; position: fixed; } Title
Октябрь 2017
Сегодня
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
P.S. Также немного отрефакторил ваш код.