Re: приемы работы с IDictionary
От: WolfHound  
Дата: 22.06.11 19:41
Оценка: 6 (1)
Здравствуйте, Visor2004, Вы писали:

V>Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?

В библиотеке немерла есть тип Hashmap[K,V] : Dictionary[K,V]
Я в свое время тоже запарился писать такой код и добавил туда пару методов:
    public Update (key : TKey, defaultValue : TValue, updateFn : TValue -> TValue) : Hashtable [TKey, TValue]
    {
      mutable value;

      unless (TryGetValue (key, out value))
        value = defaultValue;

      this[key] = updateFn(value);

      this;
    }

    public Update (key : TKey, newValue : void -> TValue, updateFn : TValue -> TValue) : Hashtable [TKey, TValue]
    {
      mutable value;

      unless (TryGetValue (key, out value))
        value = newValue();

      this[key] = updateFn(value);

      this;
    }

И получается
class Test
{
  private registeredEvents : Hashtable [ Type, System.Collections.Generic.ICollection [ PresentationEvent ] ];

  public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
  {
    def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
    _ = registeredEvents.Update(ownerType, List, l => { l.Add ( newEvent ); l });
    newEvent;
  }
}

Но есть и минусы: Создание замыканий в .НЕТ не бесплатно.
Так что если нужна скорость любой ценой, то пиши по старинке.
Или сделай макрос.

Кстати уточнять тип у локальных переменных не нужно чуть менее чем всегда.
Выделенное не нужно. Компилятор сам поймет, что к чему.
mutable existingEvents : System.Collections.Generic.ICollection [ PresentationEvent ] = null;
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: приемы работы с IDictionary
От: hardcase Пират http://nemerle.org
Дата: 22.06.11 20:08
Оценка: 6 (1)
Здравствуйте, Visor2004, Вы писали:

V>Довольно часто приходится работать со словарями, делаю обычно таким образом:


V>
V>    private registeredEvents : IDictionary [ Type, System.Collections.Generic.ICollection [ PresentationEvent ] ];

V>    public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
V>    {
V>      def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
V>      mutable existingEvents : System.Collections.Generic.ICollection [ PresentationEvent ] = null;
V>      when ( ! registeredEvents.TryGetValue ( ownerType, out existingEvents ) )
V>      {
V>        existingEvents = List ( );
V>        registeredEvents [ ownerType ] = existingEvents;
V>      }
V>      existingEvents.Add ( newEvent );
V>      newEvent;
V>    }
V>


V>Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?


Вот так слегка короче:
using Nemerle.Extensions;

private registeredEvents : IDictionary [ Type, System.Collections.Generic.ICollection [ PresentationEvent ] ];

public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
{
  def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
  mutable existingEvents;
  unless ( registeredEvents.TryGetValue ( ownerType, out existingEvents ) )
    registeredEvents [ ownerType ] = existingEvents <- List ( );
  existingEvents.Add ( newEvent );
  newEvent
}
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: приемы работы с IDictionary
От: BogdanMart Украина  
Дата: 22.06.11 17:47
Оценка: 1 (1)
Здравствуйте, catbert, Вы писали:

C>ContainsKey вам не нравится?


Если надо получить значение, то приходиться совершать две операции поиска по хеш-таблице вместо одной.
Re[2]: приемы работы с IDictionary
От: BogdanMart Украина  
Дата: 22.06.11 17:52
Оценка: 1 (1)
Здравствуйте, BogdanMart, Вы писали:

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


V>>Довольно часто приходится работать со словарями,


V>>Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?


BM>В Nemerle.dll есть тип Hashmap[K,V] : Dictionary[K,V]


Если надо именно IDictionary, напшите метод-расшырение

public static TryGetValue[K,V](this dic : IDictionary[K,V], key : K) : (V, bool)
{
  mutable v;
  (dic.TryGetValue(key, out v), v)
}


или


public static TryGetValue[K,V](this dic : IDictionary[K,V], key : K) : (V, bool)
{
  mutable v;
  _ = dic.TryGetValue(key, out v);
  v           //если ключа нету -- default(V)
}
Re[3]: приемы работы с IDictionary
От: Undying Россия  
Дата: 23.06.11 08:42
Оценка: +1
Здравствуйте, Visor2004, Вы писали:

V>Да, это очевидный способ, просто не хочется плодить типы под каждый такой случай у меня их много разных


Собственно тип здесь и не нужен, достаточно extension'а:

static void AddItem(this IDictionary<TKey, IList<TItem>> dict, TKey key, TItem item);
приемы работы с IDictionary
От: Visor2004  
Дата: 22.06.11 17:39
Оценка:
Довольно часто приходится работать со словарями, делаю обычно таким образом:

    private registeredEvents : IDictionary [ Type, System.Collections.Generic.ICollection [ PresentationEvent ] ];

    public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
    {
      def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
      mutable existingEvents : System.Collections.Generic.ICollection [ PresentationEvent ] = null;
      when ( ! registeredEvents.TryGetValue ( ownerType, out existingEvents ) )
      {
        existingEvents = List ( );
        registeredEvents [ ownerType ] = existingEvents;
      }
      existingEvents.Add ( newEvent );
      newEvent;
    }


Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re: приемы работы с IDictionary
От: catbert  
Дата: 22.06.11 17:42
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?


ContainsKey вам не нравится?
Re: приемы работы с IDictionary
От: BogdanMart Украина  
Дата: 22.06.11 17:46
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>Довольно часто приходится работать со словарями,


V>Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?


В Nemerle.dll есть тип Hashmap[K,V] : Dictionary[K,V]

унег оесть метод

TryGetVlue(key:K) : (V, bool)

те в однустрочку, возвращает тюпл


можно юзатьтак

match (d.TryGetValue(k))
{
| (_, false) => ()
| (v, _ ) =>
твой код
}
Re[2]: приемы работы с IDictionary
От: Visor2004  
Дата: 22.06.11 17:50
Оценка:
Здравствуйте, BogdanMart, Вы писали:

С таким подходом у меня получается 2 независимые ветки кода, а мне надо просто сделать доп. действие, если элемента нет, то его надо добавить перед модификацией, т.е. модификацию надо делать все время, а вот добавлять только если нету элемента в словаре.
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re: приемы работы с IDictionary
От: CodingUnit Россия  
Дата: 22.06.11 18:09
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>Довольно часто приходится работать со словарями, делаю обычно таким образом:


V>
V>    private registeredEvents : IDictionary [ Type, System.Collections.Generic.ICollection [ PresentationEvent ] ];

V>    public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
V>    {
V>      def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
V>      mutable existingEvents : System.Collections.Generic.ICollection [ PresentationEvent ] = null;
V>      when ( ! registeredEvents.TryGetValue ( ownerType, out existingEvents ) )
V>      {
V>        existingEvents = List ( );
V>        registeredEvents [ ownerType ] = existingEvents;
V>      }
V>      existingEvents.Add ( newEvent );
V>      newEvent;
V>    }
V>


V>Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?


Может быть к сведению стоит обратить внимание на интересные подходы работы с коллекциями и событиями типа Reactive Extensions (RX).

http://msdn.microsoft.com/en-us/data/gg577609
Может будет полезно.
Re: приемы работы с IDictionary
От: BogdanMart Украина  
Дата: 22.06.11 19:45
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>
V>      when ( ! registeredEvents.TryGetValue ( ownerType, out existingEvents ) )
V>      {
V>        existingEvents = List ( );
V>        registeredEvents [ ownerType ] = existingEvents;
V>      }
V>      existingEvents.Add ( newEvent );
V>


Эээ а зачем?

оператор [] всегда добавляет если нет элемента,или обновляет!
Re[2]: приемы работы с IDictionary
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.06.11 20:23
Оценка:
Здравствуйте, BogdanMart, Вы писали:

BM>Эээ а зачем?

BM>оператор [] всегда добавляет если нет элемента,или обновляет!

Дык он же не добавляет, если элемент уже есть.

У него классический случай хэш-таблицы поддерживающей несколько элементов в значении. Для такого случая можно и отдельный тип создать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: приемы работы с IDictionary
От: Visor2004  
Дата: 23.06.11 07:24
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Вот так слегка короче:

H>
H>using Nemerle.Extensions;

H>private registeredEvents : IDictionary [ Type, System.Collections.Generic.ICollection [ PresentationEvent ] ];

H>public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
H>{
H>  def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
H>  mutable existingEvents;
H>  unless ( registeredEvents.TryGetValue ( ownerType, out existingEvents ) )
H>    registeredEvents [ ownerType ] = existingEvents <- List ( );
H>  existingEvents.Add ( newEvent );
H>  newEvent
H>}
H>


Уже не плохо, в совокупности с каким-нить методом расширения избавляющим от out параметра, можно использовать, спасибо Где можно почитать про вот эту стрелочку, которая жирным выделена? да и про unless я тоже в вики ничего не увидел.
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[3]: приемы работы с IDictionary
От: _nn_ www.nemerleweb.com
Дата: 23.06.11 07:38
Оценка:
Здравствуйте, Visor2004, Вы писали:

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


H>>Вот так слегка короче:

H>>
H>>using Nemerle.Extensions;

H>>private registeredEvents : IDictionary [ Type, System.Collections.Generic.ICollection [ PresentationEvent ] ];

H>>public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
H>>{
H>>  def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
H>>  mutable existingEvents;
H>>  unless ( registeredEvents.TryGetValue ( ownerType, out existingEvents ) )
H>>    registeredEvents [ ownerType ] = existingEvents <- List ( );
H>>  existingEvents.Add ( newEvent );
H>>  newEvent
H>>}
H>>


V>Уже не плохо, в совокупности с каким-нить методом расширения избавляющим от out параметра, можно использовать, спасибо Где можно почитать про вот эту стрелочку, которая жирным выделена? да и про unless я тоже в вики ничего не увидел.


здесь
Автор: hardcase
Дата: 16.03.11


Про unless
здесь и здесь
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: приемы работы с IDictionary
От: Undying Россия  
Дата: 23.06.11 07:53
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?


class MultiDictionary<TKey, TItem> : Dictionary<TKey, List<TItem>
{
  public void AddItem(TKey key, TItem item);
}

private registeredEvents : MultiDictionary [ Type, PresentationEvent ];
public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
{
  def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
  registeredEvents.AddItem ( ownerType, newEvent );
  newEvent;
}


Реализация AddItem надеюсь понятна.
Re[2]: приемы работы с IDictionary
От: Visor2004  
Дата: 23.06.11 08:14
Оценка:
Здравствуйте, Undying, Вы писали:

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


V>>Вопрос в следующем, можно ли как-то упростить код функции Register таким образом, чтоб избавиться от изменяемой переменной и ветвления when, есть ли какой-то общепринятый красивый паттерн для таких случаев?


U>
U>class MultiDictionary<TKey, TItem> : Dictionary<TKey, List<TItem>
U>{
U>  public void AddItem(TKey key, TItem item);
U>}

U>private registeredEvents : MultiDictionary [ Type, PresentationEvent ];
U>public Register ( name : string, eventDirection : EventDirection, handlerType : Type, ownerType : Type ) : PresentationEvent
U>{
U>  def newEvent = PresentationEvent ( name, ownerType, eventDirection, handlerType );
U>  registeredEvents.AddItem ( ownerType, newEvent );
U>  newEvent;
U>}
U>


U>Реализация AddItem надеюсь понятна.


Да, это очевидный способ, просто не хочется плодить типы под каждый такой случай у меня их много разных
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re: приемы работы с IDictionary
От: _nn_ www.nemerleweb.com
Дата: 23.06.11 08:23
Оценка:
Здравствуйте, Visor2004, Вы писали:

Может PowerCollections MultiDictionary вам подойдет ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: приемы работы с IDictionary
От: Silver_S Ниоткуда  
Дата: 25.06.11 18:32
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>Да, это очевидный способ, просто не хочется плодить типы под каждый такой случай у меня их много разных


Какой каждый? Этот тип MultiDictionary по сути достаточно универсальный, чтобы для него был отдельный тип.
В котором гарантируется что не будет null значений(коллекций).

Код с неявными MultiDictionary всгда выглядит неприятно и коряво. Потому что для ключа вместо 2-х основных состояний — есть элементы или нет. Их 4. 1)Есть коллекция с элементами 2)Есть коллекция но пустая 3) вместо коллекции null 4) вобще ничего,даже ключа нет. Либо запаришся проверки делать, либо код будет ненадежный и сложный из-за неявных соглашений.
И куча вопросов можно ли делать SelectMany или на null коллекции посыпется. Что делать когда последний элемент удаляешь — присваивать null или оставлять пустую коллекцию или все вместе с ключом убивать. Это должно быть в классе инкапсулировано.

Есть аналог в .NET — ILookup, он не подходит т.к. readonly, но там если по ключу ничего не лежит, то возвращается пустой IEnumerable.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.