Thank you, Marten, for the suggestion. And Happy New Year!
I actually ended up doing that before your reply, except I had used a 
"homebrew benchmarking" implementation. I also did it with Benchee, and the 
results really weren't all that different but I've included only the 
results from Benchee below.  

Name                                 ips        average  deviation         
median 
        99th %

map replace_many                  2.69 M      371.13 ns ±10368.06%         
  0 ns         990 ns

map for + replace                 2.32 M      430.38 ns  ±8111.30%         
  0 ns         990 ns

map reduce + replace!             2.32 M      431.63 ns  ±8167.48%         
  0 ns         990 ns

map update_many                   2.05 M      488.47 ns  ±9258.19%         
  0 ns         990 ns

map for + update!                 1.64 M      609.13 ns  ±5804.57%         
  0 ns         990 ns

map reduce + update!              1.66 M      600.64 ns  ±5698.26%         
  0 ns         990 ns

keywords replace_many             1.91 M      523.22 ns  ±6849.81%         
  0 ns         990 ns

keywords for + replace!           1.84 M      544.19 ns  ±6432.10%         
  0 ns         990 ns

keywords reduce + replace!        1.82 M      550.39 ns  ±6488.68%         
  0 ns         990 ns

keywords update_many              1.78 M      561.74 ns  ±6508.52%         
  0 ns         990 ns

keywords for + update!            1.49 M      670.96 ns  ±6347.76%         
  0 ns         990 ns

keywords reduce + update!         1.46 M      686.43 ns  ±6250.71%         
  0 ns         990 ns


On Friday, December 31, 2021 at 2:05:17 AM UTC-5 w...@resilia.nl wrote:

> Putting them in a module in any file (with e.g. a `.ex` or `.exs` 
> extension) and running them from there will work.
> You might also like to look into libraries such as `Benchee` which make 
> benchmarking easier and prevent some of the pitfalls which a homebrew 
> benchmarking implementation might have.
>
> Hope this helps, and happy old year/new year :-),
>
> ~Marten
> On 31-12-2021 01:01, Paul Alexander wrote:
>
> Sorry. Would putting them in a test case be better practice? If not, do 
> you mind telling me of the correct way which would produce the most 
> indicative results? 
>
> On Thursday, December 30, 2021 at 6:24:08 PM UTC-5 José Valim wrote:
>
>> Don’t benchmark in the shell. Code in the shell is evaluated and not 
>> compiled.
>>
>> On Fri, Dec 31, 2021 at 00:14 Paul Alexander <paul.aj...@gmail.com> 
>> wrote:
>>
>>> Thanks for offering your opinion, José. I very much understand where 
>>> you're coming in regards to using Enum.reduce/3 for such an operation, but 
>>> I have found it to cause a fair amount of needless overhead especially when 
>>> there are other operations going on and the updating should be the most 
>>> trivial. Since you brought up the efficiency tradeoffs, I've put together a 
>>> few simple benchmarks below for the Map functions where the results are 
>>> from averaging 10k iterations. As you can see the performance improvement 
>>> is quite drastic, with both *_many functions being 130%+ . 
>>>
>>> iex> map
>>>
>>> %{a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10}
>>>
>>> iex> kv
>>>
>>> [a: 11, d: 22, g: 33, j: 44]
>>>
>>> iex> keys
>>>
>>> [:a, :d, :g, :j]
>>>
>>> iex(32)> Benchmark.measure(10_000, "reduce + replace!", fn -> 
>>> Enum.reduce(kv, map, fn {k, v}, acc -> Map.replace!(acc, k, v) end) end)
>>>
>>> reduce + replace! avg: 18.2396
>>>
>>> iex(33)> Benchmark.measure(10_000, "replace_many", fn -> 
>>> Map.replace_many(map, kv) end)
>>>
>>> replace_many avg: 1.0979
>>>
>>> iex(34)> Benchmark.measure(10_000, "reduce + update!", fn -> 
>>> Enum.reduce(keys, map, fn k, acc -> Map.update!(acc, k, &(&1*2)) end) end)
>>>
>>> reduce + update! avg: 48.284
>>>
>>> iex(35)> Benchmark.measure(10_000, "update_many", fn -> 
>>> Map.update_many(map, keys, &(&1*2)) end)
>>>
>>> update_many avg: 9.8719
>>> On Thursday, December 30, 2021 at 5:13:10 PM UTC-5 José Valim wrote:
>>>
>>>> Hi Paul,
>>>>
>>>> Thanks for the proposal. My personal take is that a Enum.reduce/3 + the 
>>>> relevant Map operation should be the way to go, because this can easily 
>>>> lead to a combination of replace_many, update_many, put_new_many, etc. 
>>>> Especially because the many operations likely wouldn't be any more 
>>>> efficient than the Enum.reduce/3 call.
>>>>
>>>>
>>>> On Thu, Dec 30, 2021 at 10:42 PM Paul Alexander <paul.aj...@gmail.com> 
>>>> wrote:
>>>>
>>>>> Hi everyone, 
>>>>>
>>>>> I would like to discuss the possibility of adding two new functions to 
>>>>> each of the Map and Keyword modules; replace_many/2 and update_many/3. 
>>>>> Their purpose is to update maps and keyword lists providing either a 
>>>>> keyword list of the key-value pairs which need to updated, or a list of 
>>>>> keys and a function which operates on the existing values of those keys.
>>>>>
>>>>> Far too often I find myself needing to call replace!/3 or update!/3 
>>>>> several times from within a pipeline, or even needing to use a 
>>>>> for-comprehension or Enum.reduce/3 to update a map in "one shot", when it 
>>>>> feels like there should be a function for this. 
>>>>>
>>>>> There are a number of reasons as to why I think these functions should 
>>>>> be considered, but I'll provide only two for now:
>>>>>
>>>>>    1. There is already a way of updating multiple key-value pairs 
>>>>>    simultaneously for maps using %{map | k1 => v1, k2 => v2}. But this 
>>>>>    unfortunately does not support passing a literal keyword list after 
>>>>> the 
>>>>>    cons operator. 
>>>>>       - My first instinct was to see if I could expand the special 
>>>>>       update syntax to handle keyword lists, but I wasn't able to find 
>>>>> where it 
>>>>>       is in the codebase. If someone could point that out for me because 
>>>>> I'd like 
>>>>>       to learn how it works, I'd greatly appreciate it. 
>>>>>    2. It would be somewhat analogous to Kernel.struct!/2, where 
>>>>>    keyword lists can be passed as the second argument to update several 
>>>>> fields 
>>>>>    within a struct. Seeing as how structs are maps, it only makes sense 
>>>>> there 
>>>>>    should be a way that maps could be updated in a similar manner from 
>>>>> within 
>>>>>    the Map module. 
>>>>>
>>>>>
>>>>> I have already implemented the four functions, complete with docs, 
>>>>> examples, and passing tests. But I wanted confirmation from the core team 
>>>>> if a PR is welcome for this addition. Any opinions?
>>>>>
>>>> -- 
>>>>> You received this message because you are subscribed to the Google 
>>>>> Groups "elixir-lang-core" group.
>>>>> To unsubscribe from this group and stop receiving emails from it, send 
>>>>> an email to elixir-lang-co...@googlegroups.com.
>>>>> To view this discussion on the web visit 
>>>>> https://groups.google.com/d/msgid/elixir-lang-core/7c79a2b8-3a3c-48f9-a4d0-7d2e07c851e4n%40googlegroups.com
>>>>>  
>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/7c79a2b8-3a3c-48f9-a4d0-7d2e07c851e4n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>> .
>>>>>
>>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "elixir-lang-core" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to elixir-lang-co...@googlegroups.com.
>>>
>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/elixir-lang-core/63cf4231-5747-4f8e-99f7-87a68a7ab664n%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/elixir-lang-core/63cf4231-5747-4f8e-99f7-87a68a7ab664n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>> -- 
> You received this message because you are subscribed to the Google Groups 
> "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to elixir-lang-co...@googlegroups.com.
>
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/elixir-lang-core/cb88ccf3-ece7-47b5-a6d6-7ba5253482bfn%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/elixir-lang-core/cb88ccf3-ece7-47b5-a6d6-7ba5253482bfn%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/939b72ba-4438-4c2b-8412-2b8f43b23d48n%40googlegroups.com.

Reply via email to