Re[5]: Dictionary<X, Dictionary<Y, Z>>
От: Sinix  
Дата: 18.10.15 08:58
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>А вообще, вот такое поведение, где operator[] создаёт default в случае отсутствия — очень удобно.


Согласен. Реально удобно для словарей, в которые постоянно складываются данные.

Проблема в том, код в дотнете заточен под политику "все потенциально проблемные действия должны быть оформлены явно".
Добавление элемента в словарь при получении значения очень неочевидно и может выстрелить самым внеапным способом. Например, сценарий "один раз заполнили — потом возвращаем что есть": в теории словарь readonly, по факту — незаметно заполняется "мусорными" ключами.

В общем, с точки зрения оф.гадлайнов для дотнета, такая штука должна предлагаться как приятное дополнение а не быть включённой в дефолтный контейнер
Re[5]: Dictionary<X, Dictionary<Y, Z>>
От: agat50  
Дата: 18.10.15 09:06
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>А вообще, вот такое поведение, где operator[] создаёт default в случае отсутствия — очень удобно. Потому что обычно default является нейтральным элементом относительно применяемых операций. Простой пример это подсчёт количества вхождений — ++count[id], или например конкатенация строк result_string[id] += s;, или случай ТС со вложенными контейнерами.


Дефолтное значение это обычно null=) И далеко не каждый класс имеет дефолтный конструктор. Имхо лучше не надо такое добавлять.
Re[5]: Dictionary<X, Dictionary<Y, Z>>
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.10.15 09:12
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Это понятно. В STL есть отдельный метод find который не создаёт ничего, а только ищет.
EP>А вообще, вот такое поведение, где operator[] создаёт default в случае отсутствия — очень удобно. Потому что обычно default является нейтральным элементом относительно применяемых операций. Простой пример это подсчёт количества вхождений — ++count[id], или например конкатенация строк result_string[id] += s;, или случай ТС со вложенными контейнерами.
А для классов default(T) будет null. И не всегда нужен 0 по умолчанию для чисел.
По уму нужно передавать в конструктор словаря конструктор значения по умолчанию.
Тогда
d.GetOrAdd(ключ) будет возвращать значение по умолчанию. И логика понятна.
и солнце б утром не вставало, когда бы не было меня
Re[6]: Dictionary<X, Dictionary<Y, Z>>
От: Evgeny.Panasyuk Россия  
Дата: 18.10.15 09:36
Оценка: +1
Здравствуйте, agat50, Вы писали:

EP>>А вообще, вот такое поведение, где operator[] создаёт default в случае отсутствия — очень удобно. Потому что обычно default является нейтральным элементом относительно применяемых операций. Простой пример это подсчёт количества вхождений — ++count[id], или например конкатенация строк result_string[id] += s;, или случай ТС со вложенными контейнерами.

A>Дефолтное значение это обычно null=)

Это только при pointer/reference-semantics. У value-типов, превалирующих в C++, обычно есть вполне конкретный дефолт-конструктор, и это очень удобно.

A>И далеко не каждый класс имеет дефолтный конструктор.


Без проблем. Нет дефолтного конструктора — метод нельзя использовать, он не работает — ошибка компиляции. Если есть — то можно.
Re[6]: Dictionary<X, Dictionary<Y, Z>>
От: Evgeny.Panasyuk Россия  
Дата: 18.10.15 09:40
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>По уму нужно передавать в конструктор словаря конструктор значения по умолчанию.

S>Тогда
S> d.GetOrAdd(ключ) будет возвращать значение по умолчанию. И логика понятна.

Либо тип-wrapper, у которого будет другой конструктор — так не будет оверхеда на хранение значения.
Либо просто отдельная функция как уже выше предлагали, а-ля get_or_default(map, key, default).
Re[7]: Dictionary<X, Dictionary<Y, Z>>
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.10.15 10:00
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Serginio1, Вы писали:


S>>По уму нужно передавать в конструктор словаря конструктор значения по умолчанию.

S>>Тогда
S>> d.GetOrAdd(ключ) будет возвращать значение по умолчанию. И логика понятна.

EP>Либо тип-wrapper, у которого будет другой конструктор — так не будет оверхеда на хранение значения.

EP>Либо просто отдельная функция как уже выше предлагали, а-ля get_or_default(map, key, default).

Так есть же GetOrAdd Method в разных вариациях
Вот простейший

https://msdn.microsoft.com/en-us/library/ee378674(v=vs.110).aspx


Просто для не валуе типов нужна версия
https://msdn.microsoft.com/ru-ru/library/ee378677(v=vs.110).aspx

public TValue GetOrAdd(
    TKey key,
    Func<TKey, TValue> valueFactory
)


А с дефаултным конструктором значения код будет значительно короче, так как конструктор значения в основном всегда одинаков
То есть
Но по большому разница то не велика, если определить Func<TKey, TValue> как переменную


d.GetOrAdd(ключ)
d.GetOrAdd(ключ,Конструктор)
и солнце б утром не вставало, когда бы не было меня
Отредактировано 18.10.2015 10:42 Serginio1 . Предыдущая версия .
Re: Dictionary<X, Dictionary<Y, Z>>
От: T4r4sB Россия  
Дата: 18.10.15 11:38
Оценка:
Dictionary<Pair<X,Y>, Z>
А если тебе нужна возможность выбора по отдельным ключам — это уже базу данных мути.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: Dictionary<X, Dictionary<Y, Z>>
От: Kolesiki  
Дата: 18.10.15 12:30
Оценка: -1
Здравствуйте, _NN_, Вы писали:

_NN>Использование простого Dictionary не очень удобно, т.к. добавление или изменение требует нескольких TryGetValue и Add в случае если нет элементов.


Если я правильно понял, весь сыр-бор из-за того, что какой-то умник решил вместо удобного "дефолтового значения" сыпать исключения при отсутствии ключа. В Перле (за 20 лет практического применения!) ни один не пожаловался, что есть дефолтовая величина. Отсюда простой вывод — гнать в шею этих танцоров-архитекторов и внедрять нормальный словарь.
Re[6]: Dictionary<X, Dictionary<Y, Z>>
От: _NN_ www.nemerleweb.com
Дата: 18.10.15 13:13
Оценка:
Здравствуйте, xy012111, Вы писали:


X>Далее, если нужно, мульти-словарь процесс-потоки итэдэ. Это уже делается довольно просто всего лишь несколькими методами расширения.

Это как вариант конечно.
Подумываю об этом.

X>Если рассуждать об абстрактной задаче, то

X>
_NN>>class Session : KeyValueCollection<int, Desktop> { ... }
_NN>>class Desktop : KeyValueCollection<int, Process> { ... }
X>…
X>

X>не правильно. Нужен тип Session у которого есть свойство — коллекция рабочих столов. В типе рабочего стола — список процессов итиси.

Ну вот я это и имею ввиду:
class Session { Dictionary<int, Desktop> Desktops; }
class Desktop { Dictionary<int, Process> Processes;  }
и т.д.


И чем использование будет отличаться от того же Dictionary<Dictionary<...>> ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[8]: Dictionary<X, Dictionary<Y, Z>>
От: _NN_ www.nemerleweb.com
Дата: 18.10.15 14:39
Оценка:
Здравствуйте, Ромашка, Вы писали:

Р>Здравствуйте, _NN_, Вы писали:

_NN>>Dictionary и есть хештаблица.
_NN>>Или я чего-то не понимаю ?

Р>Ну да. Так и посчитайте один хеш из всех своих параметров и храните в одном dictionary без вложенности.


А удобство пользования ?
Вместо d[x][y] писать d.Where(_ => _.X == x && _.Y == y).First() ?
Удалить вместо простого Remove придется писать намного больше кода.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: Dictionary<X, Dictionary<Y, Z>>
От: _NN_ www.nemerleweb.com
Дата: 18.10.15 14:41
Оценка: +1
Здравствуйте, Sinix, Вы писали:

_NN>>И все это вместо простых чисел ?

S>Разумеется. Потому что твоя гипотетическая простота на практике оборачивается усложнением. Вместо удобной объектной модели ты в одной коллекции хранишь кишки каждого из элементов. Мало того, что это неудобно (легко забыть и перепутать порядок ключей), так ещё и сыпется на простейших задачах вида "добавить имя к процессу".

Осталось написать код для MyCollection и перейти на C# 6
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Dictionary<X, Dictionary<Y, Z>>
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.10.15 15:06
Оценка:
Здравствуйте, _NN_, Вы писали:



_NN>На данный момент добавились методы расширения GetOrAdd и код легко переписывается в :

_NN>
_NN>d.GetOrAdd(x, _ => new Dictionary<Y,Z>()).GetOrAdd(y, _ => new Z()).CallMethod();
_NN>


Наверное проще сделать
Func<X, Y>  Конструктор1= _ => new Dictionary<Y,Z>();
Func<Y, Z>  Конструктор2= _ =>new Z();

Вызов будет более читаем
d.GetOrAdd(x, Конструктор1).GetOrAdd(y,Конструктор2).CallMethod();


Кстати у ConcurrentDictionary<TKey, TValue>.GetOrAdd — метод (TKey, Func<TKey, TValue>) родной
https://msdn.microsoft.com/ru-ru/library/ee378677(v=vs.110).aspx

Другое дело, что Конструктор значения можно было бы создавать при создании словаря.
Тогда
Вызов можно было бы сократиь до
d.GetOrAdd(x).GetOrAdd(y).CallMethod();

Func<X, Y>  Конструктор1= _ => new Dictionary<Y,Z>(Конструктор2);


То есть
d=new Dictionary<Y,Z>(Конструктор1);
и солнце б утром не вставало, когда бы не было меня
Re[9]: Dictionary<X, Dictionary<Y, Z>>
От: Ромашка Украина  
Дата: 18.10.15 16:24
Оценка:
Здравствуйте, _NN_, Вы писали:
_NN>А удобство пользования ?

Блин, хеш подсчитать, не новые объекты составлять. Вот тебе простейший со стрингом (не делай так, придумай какой-нибудь более приятный алгоритм)

public class MyCoolDictionary<T>
        where T : new()
    {
        private Dictionary<string, T> _internalDictionary = new Dictionary<string, T>();

        public T this[object x, params object[] others]
        {
            get
            {
                var hash = this.GetHash(x, others);

                if (!_internalDictionary.ContainsKey(hash))
                    _internalDictionary.Add(hash, new T());

                return _internalDictionary[hash];
            }
        }

        private string GetHash(object x, params object[] others)
        {
            var str = new StringBuilder();
            str.Append(x.GetHashCode());
            foreach (var obj in others)
                str.Append(obj.GetHashCode());

            return str.ToString();
        }
    }


_NN>Вместо d[x][y] писать d.Where(_ => _.X == x && _.Y == y).First() ?


d[x, y, z /*...*/]


Всё, что нас не убивает, ещё горько об этом пожалеет.
Re[10]: Dictionary<X, Dictionary<Y, Z>>
От: _NN_ www.nemerleweb.com
Дата: 18.10.15 16:50
Оценка:
Здравствуйте, Ромашка, Вы писали:

Р>Здравствуйте, _NN_, Вы писали:

_NN>>А удобство пользования ?

Р>Блин, хеш подсчитать, не новые объекты составлять. Вот тебе простейший со стрингом (не делай так, придумай какой-нибудь более приятный алгоритм)


Об этом я изначально и говорил, создать специализированные словари для множественных вложений.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: Dictionary<X, Dictionary<Y, Z>>
От: Vladek Россия Github
Дата: 18.10.15 22:23
Оценка: +1
Здравствуйте, _NN_, Вы писали:

_NN>Какое предложение тут будет ?


_NN>
_NN>class Session : KeyValueCollection<int, Desktop> { ... }
_NN>class Desktop : KeyValueCollection<int, Process> { ... }
_NN>class Process : KeyValueCollection<int, Thread> { ... }
_NN>class Thread : KeyValueCollection<int, Data> { ... }
_NN>class Data { ... }
_NN>


_NN>И все это вместо простых чисел ?


Я тут вижу простой список объектов Data. Если будет достаточно простым перебором списка найти нужный объект, то городить огород с вложенными словарями не требуется. Добавь в Data идентификаторы для процессов, потоков, окон, да и всё.
Re: Dictionary<X, Dictionary<Y, Z>>
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 19.10.15 07:53
Оценка:
Здравствуйте, _NN_, Вы писали:

Вместо двух словарей проще использовать один с составным ключом. Редко пеишу на C# но что типа такого

public struct MyStruct<X,Y>
    {
        public X СвойствоX;
        public Y СвойствоY;

        
        public MyStruct(X СвойствоX, Y СвойствоY)
            {
            this.СвойствоX = СвойствоX;
            this.СвойствоY = СвойствоY;
        }
        public override int GetHashCode()
        {
            //Упростим задачу и сделаем по простому
            string str= Convert.ToBase64String(BitConverter.GetBytes(СвойствоX.GetHashCode()))+ Convert.ToBase64String(BitConverter.GetBytes(СвойствоY.GetHashCode()));
            return str.GetHashCode();
        }

//Можно взять из Tuple

//internal static int CombineHashCodes(int h1, int h2)
//{
//    return (h1 << 5) + h1 ^ h2;
//}
        public override bool Equals(object obj)
        {
            if (obj.GetType()!= GetType()) return false;

            var Объект = (MyStruct<X, Y>)obj;
            return СвойствоX.Equals(Объект.СвойствоX) && СвойствоY.Equals(Объект.СвойствоY);
        }
    }
и солнце б утром не вставало, когда бы не было меня
Отредактировано 19.10.2015 8:26 Serginio1 . Предыдущая версия .
Re: Ключ string
От: johny5 Новая Зеландия
Дата: 19.10.15 08:06
Оценка:
Здравствуйте, _NN_, Вы писали:

Возможно это будет вариацией того что предлагали выше.
Индексацию можно проводить по строке. Все ваши ключи склеиваются в одну строку и по ней ищется.

Псевдо код:
string key = string.Format("{0}/{1}/{2}..", keys);
return dict[key];

Появляется возможно искать и по подстроке:
string partial_key = string.Format("{0}/{1}", key1, key2);
dict.Keys.Where(x => x.StartsWith(partial_key));

Правда это будет подороже но терпимо если кол-во значений невелико.
Re[9]: Dictionary<X, Dictionary<Y, Z>>
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 19.10.15 09:17
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, Ромашка, Вы писали:


Р>>Здравствуйте, _NN_, Вы писали:

_NN>>>Dictionary и есть хештаблица.
_NN>>>Или я чего-то не понимаю ?

Р>>Ну да. Так и посчитайте один хеш из всех своих параметров и храните в одном dictionary без вложенности.


_NN>А удобство пользования ?

_NN>Вместо d[x][y] писать d.Where(_ => _.X == x && _.Y == y).First() ?
_NN>Удалить вместо простого Remove придется писать намного больше кода.

Не намного пройтись по ключам и найти Ключи по X. Всего 2 строчки
var ключи=d.Keys.Where(key=> key.Item1==x).Select(key=> key).ToList();


foreach (var ключ in ключи) d.Remove(ключ );


Вместо  d[x][y]
d[new Tuple<X,Y>(x,y)]



Либо сделать наследника от Dictionary и использовать конструктор значения по умолчанию
http://rsdn.ru/forum/dotnet/6218191.1
Автор: Serginio1
Дата: 18.10.15
и солнце б утром не вставало, когда бы не было меня
Отредактировано 19.10.2015 9:20 Serginio1 . Предыдущая версия .
Re[10]: Dictionary<X, Dictionary<Y, Z>>
От: _NN_ www.nemerleweb.com
Дата: 19.10.15 09:24
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> Либо сделать наследника от Dictionary и использовать конструктор значения по умолчанию

S>http://rsdn.ru/forum/dotnet/6218191.1
Автор: Serginio1
Дата: 18.10.15


Либо специализированный класс и всё еще проще:
d.RemoveByFirst(x)

d[x,y]
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[11]: Dictionary<X, Dictionary<Y, Z>>
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 19.10.15 09:58
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, Serginio1, Вы писали:


S>> Либо сделать наследника от Dictionary и использовать конструктор значения по умолчанию

S>>http://rsdn.ru/forum/dotnet/6218191.1
Автор: Serginio1
Дата: 18.10.15


_NN>Либо специализированный класс и всё еще проще:

_NN>
_NN>d.RemoveByFirst(x)

_NN>d[x,y]
_NN>

Наследник проще в том, что нужно добавить всего несколько методов, но используя методы словаря плюс расширения.
специализированный класс я так понимаю будет врапером?
Хотя конечно можно все сгенерить по метаданным например T4.
А можно взять исходники и переделать под себя.
и солнце б утром не вставало, когда бы не было меня
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.