Which is a better way to write an "add or initialize"?

  • Thread starter Thread starter SlurrerOfSpeech
  • Start date Start date
Click For Summary

Discussion Overview

The discussion revolves around different approaches to writing a procedure for adding or initializing elements in a map or dictionary structure, particularly in programming languages like JavaScript, Python, Perl, C++, and C#. Participants explore the merits of various coding styles and idioms for handling this task.

Discussion Character

  • Technical explanation
  • Debate/contested

Main Points Raised

  • One participant prefers a method that minimizes conditional blocks, arguing for a streamlined approach to initialization and addition in JavaScript.
  • Another participant agrees that separating initialization and addition can enhance clarity and suggests using the or-operator idiom in JavaScript for this purpose.
  • A third participant notes that the choice of method can be language-dependent and shares a Python approach that emphasizes error handling through exception catching.
  • In Perl, a participant describes using a method that avoids negation and employs an end-line conditional for initialization.
  • A different participant mentions that in C++, the associative array automatically adds keys if they are not present, simplifying the addition process.
  • Another participant discusses a C# approach where the standard dictionary index operator throws an exception for unknown keys, leading to a specific method for adding elements.

Areas of Agreement / Disagreement

Participants express varying preferences for coding styles and idioms, indicating no consensus on a single "best" approach. Multiple competing views on the most effective method remain present throughout the discussion.

Contextual Notes

Participants highlight that the effectiveness of different methods may depend on the specific programming language and its features, as well as the context in which the code is used.

SlurrerOfSpeech
Messages
141
Reaction score
11
In my work I often find myself having to write a procedure for

"If this key is in the map, push this element to the end of the array associated with the key; otherwise, add the key and an associated array whose single element is this one".

I used to do this like

Code:
if ( key in M ) { M[key].push(elem); }
else { M[key] = [elem]; }

but now prefer to write it like

Code:
if ( !(key in M ) { M.[key] = new Array(); }
M[key].push(elem);

Why do I like this new way if the old way is equivalent?

Because I like as few conditional blocks as possible. I like to think in terms of "If not this, change that fact and move on to the same logic we will always move on to" rather than "If not this, enter a different block of logic".

Please share your thoughts on this religious doctrine.

Note: I labeled this question as JavaScript only because I had to choose a label. My code is in JavaScript, but this question can apply to other languages.
 
Technology news on Phys.org
When initialization and adding can be separated (not always the case for all data structures) then your second approach is quite common and, in my opinion, a bit more clear than the former approach. I would go with the later approach whenever possible.

Note, that in JavaScript there is another common idiom when initializing and adding that uses the or-operator. Provided that your M object only have array members, then in your case that idiom would be like
Code:
(M[key] || (M[key] = [])).push(elem);
 
In this case, the difference is so small that it's a bit moot. How one would accomplish that is also language-dependent.

In python, I'd probably follow the mantra that it's easier to ask for forgiveness:
Python:
def add_element (M, key, elem) :
    try :
        M[key].append (elem)
    except KeyError :
        M[key] = [elem]

In perl, I'd use something similar to your new method, except I'd use an end-line conditional, and to avoid not, I'd use unless:
Perl:
sub add_element($$$) {
    my ($M, $key, $elem) = @_;
    $M->{$key} = [] unless exists $M->{$key};
    push @{$M->{$key}}, $elem;
}

Update on the above: @Filip Larsen's approach also works nicely in perl:
Perl:
sub add_element($$$) {
    my ($M, $key, $elem) = @_;
    push @{$M->{$key} or $M->{$key} = []}, $elem;
}

In C++, I'd use the fact that M[key] automatically adds the key to the associative array if it's not present:
Code:
template <KeyType, ElemType>
void add_element (
    std::unordered_map<KeyType, std::vector<ElemType>>& M,
    const KeyType& key,
    const ElemType& elem)
{
    M[key].append(elem);
}
 
Last edited:
  • Like
Likes   Reactions: SlurrerOfSpeech
Now DH has started on other languages I may add that in C# (where the standard dictionary index operator getter throws exception on unknown keys) I mostly end up do something like

Code:
void AddElement<TKey,TValue>(IDictionary<TKey,ICollection<TValue>> map, TKey key, TValue value) 
{
  ICollection<TValue> values;
  if (!map.TryGet(key, out values)) {
    map[key] = values = new List<TValue>();
  }
  values.Add(value);
}
 

Similar threads

  • · Replies 25 ·
Replies
25
Views
3K
  • · Replies 31 ·
2
Replies
31
Views
3K
Replies
2
Views
2K
  • · Replies 7 ·
Replies
7
Views
4K
Replies
43
Views
5K
  • · Replies 35 ·
2
Replies
35
Views
2K
  • · Replies 28 ·
Replies
28
Views
4K
  • · Replies 9 ·
Replies
9
Views
2K
  • · Replies 4 ·
Replies
4
Views
2K
  • · Replies 3 ·
Replies
3
Views
3K