【问题标题】:Merging tagged template literal fragments : best algorithm?合并标记的模板文字片段:最佳算法?
【发布时间】:2020-09-07 08:44:17
【问题描述】:

我有一个标记模板文字片段构建器,看起来像这样:

function fragment(chunks, ...args) {
  return new Fragment(chunks, args);
};

class Fragment {
  constructor(chunks, args) {
    this.chunks = chunks;
    this.args = args;
  }
}

这个想法是能够将标记的模板文字拆分为不同的部分,并拥有一个 merge 函数,该函数将任意深度嵌套的片段树转换为 chunks 数组和 args 数组,就好像它只是一个数组一样以 :

开头的大标记模板文字
function f() {}
function g() {}

const part = fragment`A ${f} B`

const nested = fragment`C ${part} D ${g} E ${part}`

const [chunks, args] = merge(nested)

console.log(chunks) // ["C A ", " B D ", " E A ", " B"]
console.log(args) // [function f, function g, function f]

实现merge 的最佳和最有效的算法是什么?谢谢。

【问题讨论】:

  • 为什么之后在 merge 中这样做,而不是直接在 Fragment 构造函数中?你甚至不需要在那里处理递归。
  • @Bergi 因为merge 是更一般的情况。如果我有一个算法可以直接在Fragment 构造函数中合并,那么我只需要向它添加一个递归即可得到merge。所以一个或另一个解决了我的问题。

标签: javascript algorithm template-literals


【解决方案1】:

这有点难看,因为模板文字有两个 parallel arrays,但这是我要做的:

function mergeInto(target, acc, {chunks: srcChunks, args: srcArgs}) {
    const {chunks: targetChunks, args: targetArgs} = target;
    for (var i=0; i<srcArgs.length; i++) {
        acc += srcChunks[i];
        if (srcArgs[i] instanceof Fragment) {
            acc = mergeInto(target, acc, srcArgs[i]);
        } else {
            targetChunks.push(acc);
            targetArgs.push(srcArgs[i]);
            acc = "";
        }
    }
    return acc + srcChunks[i];
}

function merge(fragment) {
    const chunks = [], args = [];
    chunks.push(mergeInto({chunks, args}, "", fragment));
    return [chunks, args];
}

【讨论】:

    【解决方案2】:

    这是另一种解释,尽管在没有看到更多数据样本的情况下我对它的执行并不完全有信心。简而言之,如果在fragment函数中处理chunksargs的管理,就不需要merge函数...

    function fragment(chunks, ...args) {
      let chunksCopy = [];
      let argsCopy = [];
      for ( i = 0; i < args.length; i++ ) {
        if ( args[ i ] instanceof Fragment ) {
          chunksCopy[ i ] = chunks[ i ] + args[ i ].chunks[ 0 ];
          chunksCopy[ i + 1 ] = args[ i ].chunks[ 1 ] + chunks[ i + 1 ];
          //argsCopy.splice( i, 0, args[ i ].args[ 0 ] );
          argsCopy[ i ] = args[ i ].args[ 0 ];
        } else {
          if ( chunksCopy[ i ] == null ) {
            chunksCopy[ i ] = chunks[ i ];
          }
          argsCopy[ i ] = args[ i ];
        }
      }
      if ( chunksCopy[ i ] == null ) {
        chunksCopy[ i ] = chunks[ i ];
      }
      return new Fragment( chunksCopy, argsCopy );
    };
    
    class Fragment {
      constructor( chunks, args ) {
        this.chunks = chunks;
        this.args = args;
      }
    }
    
    function f() {}
    function g() {}
    
    const part = fragment`A ${f} B`;
    console.log( part );
    
    const nested = fragment`C ${part} D ${g} E ${part}`;
    console.log( nested )
    console.log( nested.chunks );  // ["C A ", " B D ", " E A ", " B"]
    console.log( nested.args ) // [function f, function g, function f]

    请注意,当使用“运行代码 sn-p”时,console.log( nested.args ) 似乎将第三个函数参数显示为对 f() 的第一个函数参数的引用。为了更清楚地解释结果,请在浏览器调试模式下复制并运行上述内容...

    【讨论】:

      猜你喜欢
      • 2011-06-14
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      • 2020-04-03
      • 2017-02-22
      • 2023-03-12
      • 2017-08-04
      • 2010-10-08
      相关资源
      最近更新 更多