You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用更优雅的Lodash方式反转对象并保留原键到数组?

How to invert an object with Lodash while collecting original keys into arrays (instead of overwriting)

Question

I want to invert an object using Lodash's _.invert method, but instead of losing duplicate value keys like the default _.invert does, I want to collect the original keys into arrays. I've implemented a function myself, but I feel it's not elegant enough. I'm wondering if there's a more concise, Lodash-idiomatic way to achieve this.

Here's my current implementation:

let tokens = { y: 'years', Y: 'years', M: 'months', mo: 'months', Mo: 'months', w: 'weeks', W: 'weeks', d: 'days', D: 'days', h: 'hours', H: 'hours', m: 'minutes', mi: 'minutes', Mi: 'minutes', s: 'seconds', S: 'ms' },
print = JSON.stringify(inverter(tokens), null, 2);
document.querySelector('#test').innerHTML = print;

function inverter(obj) {
  let out = {};
  _.forOwn(obj, (o, k) => {
    out[o] = _.concat(out[o] || [], [k]);
  });
  return out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
<pre id="test"></pre>
---

## Answer
Absolutely! There's a much more Lodash-idiomatic way to do this using `_.transform`—a method specifically designed for transforming objects/arrays into new structures. It's cleaner than manually initializing an empty object and looping through it, and fits better with Lodash's functional programming style.

Here's the optimized version:
```javascript
function inverter(obj) {
  return _.transform(obj, (result, value, key) => {
    // Push the key to the array; initialize the array if it doesn't exist
    _.push(result[value] || (result[value] = []), key);
  }, {});
}

If you prefer a more compact one-liner (though readability should take priority), you can write:

const inverter = obj => _.transform(obj, (res, val, key) => _.push(res[val] || (res[val] = []), key), {});

Why this is better:

  • Lodash-aligned: _.transform is purpose-built for object transformation scenarios, replacing the manual accumulator + loop pattern with a more concise, idiomatic approach.
  • Less redundant logic: The short-circuit assignment result[value] || (result[value] = []) eliminates the need for separate checks and _.concat calls, making the code more efficient.
  • Pure functional style: Avoids modifying an external variable (the out object in your original code), keeping the logic self-contained.

As an alternative, you could also use _.groupBy combined with _.mapValues, though this involves two passes over the object (so _.transform is slightly more performant):

function inverter(obj) {
  return _.mapValues(_.groupBy(obj, val => val), group => _.map(group, (_, key) => key));
}

Both approaches will produce the desired output:

{
  "years": ["y", "Y"],
  "months": ["M", "mo", "Mo"],
  "weeks": ["w", "W"],
  "days": ["d", "D"],
  "hours": ["h", "H"],
  "minutes": ["m", "mi", "Mi"],
  "seconds": ["s"],
  "ms": ["S"]
}

内容的提问来源于stack exchange,提问作者tao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:59:24