减少 JavaScript 对象中的重复项

发布于 2024-10-10 22:27:12 字数 414 浏览 8 评论 0原文

我有一个像这样的对象:

{
    a : 'foo',
    b : 'bar',
    c : 'foo',
    d : 'baz',
    e : 'bar'
}

我想减少重复项,例如:

{
    ac : 'foo',
    be : 'bar',
    d : 'baz'
}

有什么好的方法可以做到这一点?

一些警告:

  • 只会有少量的配对。 (目前有 7 个;我可以想象它会增加到 20 个。)
  • 初始属性名称将仅是单个字符,如示例中所示
  • 。值可能会达到数百个字符。
  • 速度和代码长度都非常重要,但考虑到行数较少,代码清晰度可能仍然是最重要的。

I've got an object like:

{
    a : 'foo',
    b : 'bar',
    c : 'foo',
    d : 'baz',
    e : 'bar'
}

I want to reduce the duplicates like:

{
    ac : 'foo',
    be : 'bar',
    d : 'baz'
}

What's a good way to do that?

A few caveats:

  • There will only ever be a small number of pairs. (Currently there are 7; I could imagine it going up to, say, 20.)
  • The initial property names will only ever be a single character, like in the example
  • The values could potentially run to several hundred characters.
  • both speed and code-length are highly important, but given the small number of rows, code clarity is probably still most important.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

帅哥哥的热头脑 2024-10-17 22:27:13
var Reduce = function(obj)
{
  var temp = {};
  var val = "";

  for (var prop in obj)
  {
    val = obj[prop];
    if (temp[val])
      temp[val] = temp[val] + prop.toString();
    else
      temp[val] = prop.toString();
  }

  var temp2 = {};

  for (var prop in temp)
  {
    val = temp[prop];
    temp2[val] = prop.toString();
  }

  return temp2;
};

用作:

var obj = {
  a :"foo",
  b : "bar",
  c : "foo",
  d : "bar", 
  e : "bar"
};

var ob2 = Reduce(obj);
var Reduce = function(obj)
{
  var temp = {};
  var val = "";

  for (var prop in obj)
  {
    val = obj[prop];
    if (temp[val])
      temp[val] = temp[val] + prop.toString();
    else
      temp[val] = prop.toString();
  }

  var temp2 = {};

  for (var prop in temp)
  {
    val = temp[prop];
    temp2[val] = prop.toString();
  }

  return temp2;
};

Use as:

var obj = {
  a :"foo",
  b : "bar",
  c : "foo",
  d : "bar", 
  e : "bar"
};

var ob2 = Reduce(obj);
黄昏下泛黄的笔记 2024-10-17 22:27:13

这是我能得到的最短的:

var obj, newObj = {}; // obj is your original
for (var i in obj) {
    if (!obj.hasOwnProperty(i)) continue;
    for (var j in newObj) {
        if (newObj.hasOwnProperty(j) && newObj[j] === obj[i]) break;
        j = "";
    }
    newObj[i + j] = obj[i];
    j && delete newObj[j];
}

解释:

  • 它循环遍历原始对象 obj 中的每个项目,并生成一个新对象 newObj >。
  • 对于原始文件中的每个项目,它都会在半生成的 newObj 中搜索相同的值。 - 结果是j,如果找到则为属性名称,如果未找到则为空字符串。
  • 无论哪种情况,新对象都需要一个与原始对象中当前属性同名的属性,再加上 j 值。
  • 它还会删除 newObj 中找到的属性(如果有),以防止构造重复项。

诚然,在循环内设置j = "" 效率很低。这可以很容易地替换为最初设置为 "" 的第二个变量,仅在找到匹配时设置为 j 。不过,我决定追求简单。

This is the shortest I could get it:

var obj, newObj = {}; // obj is your original
for (var i in obj) {
    if (!obj.hasOwnProperty(i)) continue;
    for (var j in newObj) {
        if (newObj.hasOwnProperty(j) && newObj[j] === obj[i]) break;
        j = "";
    }
    newObj[i + j] = obj[i];
    j && delete newObj[j];
}

Explanation:

  • It loops through each item in the original object, obj, and produces a new object, newObj.
  • For each item in the original, it searches the half-produced newObj for the same value. - The result is j, either the name of the property if found, or an empty string if not.
  • In either case, the new object needs a property of the same name as the current property in the original object, plus this value of j.
  • It also deletes the found property in newObj if there was one, to prevent duplicates being constructed.

Admittedly, setting j = "" within the loop is inefficient. This can easily be replaced with a second variable set to "" initially, and j only if a match is found. I decided to go for simplicity though.

心病无药医 2024-10-17 22:27:13

如果没有更高种类的库,只需循环每对(使用hasOwnProperty)并将键添加/附加到直方图,其中直方图键是对值,直方图值是连接的键。然后反转直方图的键/值。

编辑:如果初始值不是字符串(并且不能可逆映射),则现有的“身份哈希”库可能仍然可以使上述方法发挥作用。

或者,您可以映射为 [[k,v],...] 并排序,然后使用类似于 桶排序(想象它已经排序)以合并输出过程中“相等键”的值。

它可能是这样的(虽然代码可能有错误,但该方法是合理的——只要您有办法比较这些值,它也可以将任意对象作为值使用):

var _f = []
for (var k in map) {
  if (map.hasOwnProperty(k)) {
    _f.push({k: k, v: map[k]})
  }
}
// you could also sort on name (a.k), if it's important
// this makes it more versatile and deterministic in output
// ordering than the histogram method above
var f = _f.sort(function (a, b) { return a.v < b.v ? 1 : a.v > b.v ? -1 : 0 })

var res = {}
var prev
var name = ""
// after the sort all {k:,v:} objects with the same values will be grouped
// together so we only need to detect the change to the next value
// and everything prior to that gets the merged key
for (var i = 0; i < f.length; i++) {
  var p = f[i]
  if (prev != p.v && name) {
    res[name] = prev
    name = ""
  } else {
    name = name + p.k
  }
  prev = p.v
}
if (name) { // don't forget last set of values
  res[name] = prev
}

// have res

Without a higher-kind library just loop each pair (use hasOwnProperty) and add/append the key to a histogram where the histogram key is the pair value and the histogram values are the concatenated keys. Then reverse the key/values of the histogram.

Edit: If the initial values are not strings (and don't map reversibly) then an existing 'identity hash' library might still enable the above approach to work.

Alternatively, you can map to say, [[k,v],...] and sort and then use an approach similar to a bucket sort (imagine it's already sorted) to merge values of "equal keys" in the output pass.

It may go like this (while the code may have bugs, the approach is sound -- it will also work with arbitrary objects as values so long as you have a way to compare the values):

var _f = []
for (var k in map) {
  if (map.hasOwnProperty(k)) {
    _f.push({k: k, v: map[k]})
  }
}
// you could also sort on name (a.k), if it's important
// this makes it more versatile and deterministic in output
// ordering than the histogram method above
var f = _f.sort(function (a, b) { return a.v < b.v ? 1 : a.v > b.v ? -1 : 0 })

var res = {}
var prev
var name = ""
// after the sort all {k:,v:} objects with the same values will be grouped
// together so we only need to detect the change to the next value
// and everything prior to that gets the merged key
for (var i = 0; i < f.length; i++) {
  var p = f[i]
  if (prev != p.v && name) {
    res[name] = prev
    name = ""
  } else {
    name = name + p.k
  }
  prev = p.v
}
if (name) { // don't forget last set of values
  res[name] = prev
}

// have res
指尖微凉心微凉 2024-10-17 22:27:13

遍历对象的每个属性并构造另一个对象,其中键是第一个对象的值,值是键列表(从第一个开始)。然后你返回第二个对象并得出最终结果。

像这样:

function noDupes(obj) {
  var o2 = {};
  for (var k in obj) {
    if (obj.hasOwnProperty(k)) {
      var list = o2[obj[k]] || [];
      list.push(k);
      o2[obj[k]] = list;
    }
  }
  var rv = {};
  for (k in o2) {
    if (o2.hasOwnProperty(k))
      rv[o2[k].join('')] = k;
  }
  return rv;
}

现在,如果原始对象的值不是字符串,那么事情会变得更加复杂:只有字符串可以作为 Javascript 对象中的属性键。在这种情况下,您可以寻找更通用的哈希实现。如果您的对象往往非常小(少于 10 个左右的属性),您可以编写 n2 版本,您只需迭代属性,然后对每个属性再次迭代。但是,如果您的对象可能很大并且您必须多次执行此操作,那么这可能是一个坏主意。

Go through each property of the object and construct another object, where the keys are the values of the first, and the values are lists of keys (from the first). Then you go back through that second object and make the final result.

Something like this:

function noDupes(obj) {
  var o2 = {};
  for (var k in obj) {
    if (obj.hasOwnProperty(k)) {
      var list = o2[obj[k]] || [];
      list.push(k);
      o2[obj[k]] = list;
    }
  }
  var rv = {};
  for (k in o2) {
    if (o2.hasOwnProperty(k))
      rv[o2[k].join('')] = k;
  }
  return rv;
}

Now, if the values of the original object are not strings, then things get more involved: only strings can be property keys in a Javascript object. You could look around for a more general hash implementation, in that case. If your objects tend to be pretty small (fewer than 10 or so properties) you could write up the n2 version, where you simply iterate over the properties and then iterate again for each one. That would probably be a bad idea however if your objects might be large and you have to perform this operation a lot.

二智少女猫性小仙女 2024-10-17 22:27:13

如果我完全不同意,请原谅我,但在我看来,你组合这些的方式,你得到的键和值是错误的。这又如何呢?

{
    'foo': ['a', 'c'],
    'bar': ['b', 'e'],
    'baz': ['d']
}

应该很容易转换:(

flippedObj = {};
for (var letter in obj) {
    if (obj.hasOwnProperty(letter)) {
        var letters = flippedObj[obj[letter]];
        if (letters === undefined) {
            letters = [];
            flippedObj[obj[letter]] = letters;
        }

        letters.push(letter);
    }
}

大脑编译;可能有一些错误。)

Forgive me if I'm completely out, but it seems to me that the way you're combining these, you've got the keys and the values the wrong way around. What about this?

{
    'foo': ['a', 'c'],
    'bar': ['b', 'e'],
    'baz': ['d']
}

Should be easy enough to convert:

flippedObj = {};
for (var letter in obj) {
    if (obj.hasOwnProperty(letter)) {
        var letters = flippedObj[obj[letter]];
        if (letters === undefined) {
            letters = [];
            flippedObj[obj[letter]] = letters;
        }

        letters.push(letter);
    }
}

(Brain-compiled; there might be a couple of errors.)

墨离汐 2024-10-17 22:27:13

从使用字典以翻转方式对标签进行计数的reduce 开始。非常高效的方式,因为它使用内置的字典支持,没有 for 循环等。

var flipped = Object.keys(input).reduce(function(a,b){
  var tag = input[b];
  a[tag] = (a[tag] || '') + b;
  return a;
}, {});

返回具有翻转格式的对象:

// {foo: "ac", bar: "be", baz: "d"}

然后只需翻转格式:

Object.keys(flipped).reduce(function(a,b){
  a[flipped[b]]=b;
  return a;
}, {});

输出:

// {ac: "foo", be: "bar", d: "baz"}

Start with a reduce that uses a dictionary to count the tags in a flipped way. Very performant way since it uses the built in dictionary support, no for loops etc.

var flipped = Object.keys(input).reduce(function(a,b){
  var tag = input[b];
  a[tag] = (a[tag] || '') + b;
  return a;
}, {});

Returns an object with flipped format:

// {foo: "ac", bar: "be", baz: "d"}

Then just flip the format:

Object.keys(flipped).reduce(function(a,b){
  a[flipped[b]]=b;
  return a;
}, {});

Output:

// {ac: "foo", be: "bar", d: "baz"}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文