lib.lists.replaceElemAt: init

It's very easy to resort to lib.take + lib.drop to accomplish this, but it's not obvious that it actually performs quite badly.

Replacing an item in a list should be a relative common operation.
This commit is contained in:
Glen Huang
2026-01-07 23:22:02 +08:00
parent 865f635c17
commit 0445cc8aab
3 changed files with 51 additions and 0 deletions

View File

@@ -295,6 +295,7 @@ let
elemAt
isList
concatAttrValues
replaceElemAt
;
inherit (self.strings)
concatStrings

View File

@@ -2019,4 +2019,41 @@ rec {
:::
*/
concatAttrValues = set: concatLists (attrValues set);
/**
Replaces a list's nth element with a new element
# Inputs
`list`
: Input list
`idx`
: index to replace
`newElem`
: new element to replace with
# Type
```
replaceElemAt :: [a] -> int - b -> [a]
```
# Examples
:::{.example}
## `replaceElemAt` usage example
```nix
lib.replaceElemAt` [1 2 3] 0 "a"
=> ["a" 2 3]
```
:::
*/
replaceElemAt =
list: idx: newElem:
assert lib.assertMsg (idx >= 0 && idx < length list)
"'lists.replaceElemAt' called with index ${toString idx} on a list of size ${toString (length list)}";
genList (i: if i == idx then newElem else elemAt list i) (length list);
}

View File

@@ -4909,4 +4909,17 @@ runTests {
targetTarget = "prefix-tt";
};
};
testReplaceElemAt = {
expr = lib.replaceElemAt [ 1 2 3 ] 1 "a";
expected = [
1
"a"
3
];
};
testReplaceElemAtOutOfRange = testingThrow (lib.replaceElemAt [ 1 2 3 ] 5 "a");
testReplaceElemAtNegative = testingThrow (lib.replaceElemAt [ 1 2 3 ] (-1) "a");
}