代码之家  ›  专栏  ›  技术社区  ›  srghma

nix函数递归合并属性/记录并连接数组

nix
  •  0
  • srghma  · 技术社区  · 7 年前

    有人知道合并记录列表的功能吗

    • 如果要合并的所有值都是记录,则递归合并它们
    • 如果要合并的所有值都是数组-连接数组
    • 如果无法合并值,则首选后一个值

    recursiveMergeAttrs [
      { a = "x"; c = "m"; list = [1]; }
      { a = "y"; b = "z"; list = [2]; }
    ]
    
    returns
    
    { a = "y"; b = "z"; c="m"; list = [1 2] }
    

    例2

    recursiveMergeAttrs [
      {
        boot.loader.grub.enable = true;
        boot.loader.grub.device = "/dev/hda";
      }
      {
        boot.loader.grub.device = "";
      }
    ]
    
    returns
    
    {
      boot.loader.grub.enable = true;
      boot.loader.grub.device = "";
    }
    

    附笔。

    recursiveUpdate不工作

    recursiveMergeAttrs = listOfAttrsets: lib.fold (attrset: acc: lib.recursiveUpdate attrset acc) {} listOfAttrsets
    
    recursiveMergeAttrs [ { a = "x"; c = "m"; list = [1]; } { a = "y"; b = "z"; list = [2]; } ]
    
    returns 
    
    { a = "y"; b = "z"; c = "m"; list = [ 2 ]; }
    
    
    1 回复  |  直到 7 年前
        1
  •  3
  •   srghma    6 年前

    { lib, ... }:
    
    with lib;
    
    /*
      Merges list of records, concatenates arrays, if two values can't be merged - the latter is preferred
    
      Example 1:
        recursiveMerge [
          { a = "x"; c = "m"; list = [1]; }
          { a = "y"; b = "z"; list = [2]; }
        ]
    
        returns
    
        { a = "y"; b = "z"; c="m"; list = [1 2] }
    
      Example 2:
        recursiveMerge [
          {
            a.a = [1];
            a.b = 1;
            a.c = [1 1];
            boot.loader.grub.enable = true;
            boot.loader.grub.device = "/dev/hda";
          }
          {
            a.a = [2];
            a.b = 2;
            a.c = [1 2];
            boot.loader.grub.device = "";
          }
        ]
    
        returns
    
        { a = { a = [ 1 2 ]; b = 2; c = [ 1 2 ]; }; boot = { loader = { grub = { device = ""; enable = true; }; }; }; }
    
    */
    
    let
    
    recursiveMerge = attrList:
      let f = attrPath:
        zipAttrsWith (n: values:
          if tail values == []
            then head values
          else if all isList values
            then unique (concatLists values)
          else if all isAttrs values
            then f (attrPath ++ [n]) values
          else last values
        );
      in f [] attrList;
    
    
    in
    
    recursiveMerge