mirror of
https://github.com/NixOS/nix
synced 2025-06-25 10:41:16 +02:00
Introduce builtins.groupBy primop
This function is very useful in nixpkgs, but its implementation in Nix itself is rather slow due to it requiring a lot of attribute set and list appends.
This commit is contained in:
parent
2ff71b0213
commit
90700736c7
3 changed files with 55 additions and 0 deletions
|
@ -2928,6 +2928,56 @@ static RegisterPrimOp primop_partition({
|
|||
.fun = prim_partition,
|
||||
});
|
||||
|
||||
static void prim_groupBy(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
state.forceList(*args[1], pos);
|
||||
|
||||
ValueVectorMap attrs;
|
||||
|
||||
for (auto vElem : args[1]->listItems()) {
|
||||
Value res;
|
||||
state.callFunction(*args[0], *vElem, res, pos);
|
||||
string name = state.forceStringNoCtx(res, pos);
|
||||
Symbol sym = state.symbols.create(name);
|
||||
auto vector = attrs.try_emplace(sym, ValueVector()).first;
|
||||
vector->second.push_back(vElem);
|
||||
}
|
||||
|
||||
state.mkAttrs(v, attrs.size());
|
||||
|
||||
for (auto & i : attrs) {
|
||||
Value * list = state.allocAttr(v, i.first);
|
||||
auto size = i.second.size();
|
||||
state.mkList(*list, size);
|
||||
memcpy(list->listElems(), i.second.data(), sizeof(Value *) * size);
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_groupBy({
|
||||
.name = "__groupBy",
|
||||
.args = {"f", "list"},
|
||||
.doc = R"(
|
||||
Groups elements of *list* together by the string returned from the
|
||||
function *f* called on each element. It returns an attribute set
|
||||
where each attribute value contains the elements of *list* that are
|
||||
mapped to the same corresponding attribute name returned by *f*.
|
||||
|
||||
For example,
|
||||
|
||||
```nix
|
||||
builtins.groupBy (builtins.substring 0 1) ["foo" "bar" "baz"]
|
||||
```
|
||||
|
||||
evaluates to
|
||||
|
||||
```nix
|
||||
{ b = [ "bar" "baz" ]; f = [ "foo" ]; }
|
||||
```
|
||||
)",
|
||||
.fun = prim_groupBy,
|
||||
});
|
||||
|
||||
static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceFunction(*args[0], pos);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue