From eaef17bcaf8b28de19856a31a0e77ee917dbe51e Mon Sep 17 00:00:00 2001 From: preciz Date: Fri, 12 Jun 2026 19:33:28 +0200 Subject: [PATCH] Optimize Keyword.pop/3, pop!/2, and pop_lazy/3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminate redundant list traversal by calling :lists.keyfind + delete_key directly instead of going through fetch/2 + delete/2. The old code performed 3 traversals when the key was present: 1. :lists.keyfind (inside fetch) 2. :lists.keymember (inside delete — redundant) 3. delete_key (inside delete) The new code performs 2 traversals: 1. :lists.keyfind (find the value) 2. delete_key (remove all matching entries) Benchmark shows ~1.15x speedup on avg (noisy system) --- lib/elixir/lib/keyword.ex | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/elixir/lib/keyword.ex b/lib/elixir/lib/keyword.ex index f6f57e8b7ce..984838066c5 100644 --- a/lib/elixir/lib/keyword.ex +++ b/lib/elixir/lib/keyword.ex @@ -1342,9 +1342,9 @@ defmodule Keyword do """ @spec pop(t, key, default) :: {value | default, t} def pop(keywords, key, default \\ nil) when is_list(keywords) and is_atom(key) do - case fetch(keywords, key) do - {:ok, value} -> {value, delete(keywords, key)} - :error -> {default, keywords} + case :lists.keyfind(key, 1, keywords) do + {^key, value} -> {value, delete_key(keywords, key)} + false -> {default, keywords} end end @@ -1369,9 +1369,9 @@ defmodule Keyword do @doc since: "1.10.0" @spec pop!(t, key) :: {value, t} def pop!(keywords, key) when is_list(keywords) and is_atom(key) do - case fetch(keywords, key) do - {:ok, value} -> {value, delete(keywords, key)} - :error -> raise KeyError, key: key, term: keywords + case :lists.keyfind(key, 1, keywords) do + {^key, value} -> {value, delete_key(keywords, key)} + false -> raise KeyError, key: key, term: keywords end end @@ -1434,9 +1434,9 @@ defmodule Keyword do @spec pop_lazy(t, key, (-> value)) :: {value, t} def pop_lazy(keywords, key, fun) when is_list(keywords) and is_atom(key) and is_function(fun, 0) do - case fetch(keywords, key) do - {:ok, value} -> {value, delete(keywords, key)} - :error -> {fun.(), keywords} + case :lists.keyfind(key, 1, keywords) do + {^key, value} -> {value, delete_key(keywords, key)} + false -> {fun.(), keywords} end end