JS对象数组按键查找并合并

时间:2018-10-03 11:13:53

标签: javascript arrays object

拥有一个包含对象的数组,通过tenant_question_idtenant_option_id查找对象,并且必须合并other1other2(没有"" ),并在数组中具有唯一的obj

输入

[
  {
    tenant_question_id: "3",
    tenant_option_id: "22",
    other1: "$20,000.00",
    other2: ""
  },
  {
    tenant_question_id: "3",
    tenant_option_id: "22",
    other1: "",
    other2: "on"
  },
  {
    tenant_question_id: "3",
    tenant_option_id: "23",
    other1: "",
    other2: ""
  },
  {
    tenant_question_id: "3",
    tenant_option_id: "23",
    other1: "$ 500.00",
    other2: ""
  }
]

预期结果

[
  {
    tenant_question_id: "3",
    tenant_option_id: "22",
    other1: "$20,000.00",
    other2: "on"
  },
  {
    tenant_question_id: "3",
    tenant_option_id: "23",
    other1: "$ 500.00",
    other2: ""
  }
]

尝试_.filter_.omit找不到它。有什么想法吗?

4 个答案:

答案 0 :(得分:0)

通过> x <- seq_len(ncol(cc)) > cc[, c(NA, x[-1])] == 1 & cc[, c(NA, head(x, -1))] == -1 [,1] [,2] [,3] [1,] NA FALSE NA [2,] NA TRUE FALSE tenant_question_id的键创建索引,并在每次迭代中合并相关属性。然后只需获取索引的值即可。

tenant_option_id

答案 1 :(得分:0)

以下代码可以解决问题:

const mergedData = input.reduce((resultArray, tenantData) => {
  const index = resultArray.findIndex(entry => entry.tenant_question_id === tenantData.tenant_question_id && entry.tenant_option_id === tenantData.tenant_option_id);
  if (index!==-1) {
    const existingData = resultArray[index];
    if (!existingData.other1) {
      existingData.other1 = tenantData.other1;
    }
    if (!existingData.other2) {
      existingData.other2 = tenantData.other2;
    }
  } else {
    resultArray.push(tenantData);
  }
  return resultArray;
}, []);

基本上遍历数组,然后逐渐填充结果数组。对于每个项目,检查是否已经存在具有tenant_question_id和ten​​ant_option_id的项目,如果存在,则在现有对象上具有othery值(“”)的情况下,我们将覆盖other1和other2。如果不存在,则推送当前对象。

这确实存在以下问题:如果存在多个具有相同选项和键的对象,并且两个other2或两个other1都设置为非字符串值,则将使用迭代列表中的最新值。我假设您的数据集不包含此类条目。

答案 2 :(得分:0)

crocksramda功能库的帮助下,您可以采用或多或少的声明式样式。

const { groupWith, eqProps, equals } = R
const { assign, map, reduce, compose } = crocks

const data = [
  {tenant_question_id: "3", tenant_option_id: "22", other1: "$ 20,000.00", other2: ""},
  {tenant_question_id: "3", tenant_option_id: "22", other1: "", other2: "on"},
  {tenant_question_id: "3", tenant_option_id: "23", other1: "", other2: ""},
  {tenant_question_id: "3", tenant_option_id: "23", other1: "$ 500.00", other2: ""}
];

const expected = [
  {tenant_question_id: "3", tenant_option_id: "22", other1: "$ 20,000.00", other2: "on"},
  {tenant_question_id: "3", tenant_option_id: "23", other1: "$ 500.00", other2: ""}
];

// This could be composed of entries, fromEntries, and filter,
// but this approach saves an iteration.
const stripFalsyValues = t =>
  Object.entries(t)
    .reduce((a, [k, v]) => ({...a, ...(v && {[k]: v})}), {})

const mergeAll = reduce(assign, {})

const isSameTenantOptionId = eqProps('tenant_option_id')

const groupByTenantOptionId = groupWith(isSameTenantOptionId)

const mergeTenants = compose(
  map(mergeAll),
  groupByTenantOptionId,
  map(stripFalsyValues)
)

const result = mergeTenants(data)


console.log({expected, result})
<script src="https://unpkg.com/crocks/dist/crocks.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js" integrity="sha256-YN22NHB7zs5+LjcHWgk3zL0s+CRnzCQzDOFnndmUamY=" crossorigin="anonymous"></script>

请注意,关于第二个结果对象中缺少的other2: "",可以使用UI的默认属性在边缘进行处理。如果绝对必须传递空字符串,则可以将一些assignWhen = when(undefinedOption2, assign({option2: ""})

组合在一起

答案 3 :(得分:0)

我刚刚做了这个,它恰好返回您想要的输出。

var data = [{
    tenant_question_id: "3",
    tenant_option_id: "22",
    other1: "$20,000.00",
    other2: ""
  },
  {
    tenant_question_id: "3",
    tenant_option_id: "22",
    other1: "",
    other2: "on"
  },
  {
    tenant_question_id: "3",
    tenant_option_id: "23",
    other1: "",
    other2: ""
  },
  {
    tenant_question_id: "3",
    tenant_option_id: "23",
    other1: "$ 500.00",
    other2: ""
  }
];

data = data.map(function(item, index, arr) {

  // We remove the current mapped item from arr(self)
  // So we can search within an arr that doesn't contain our "item" at the "index" position
  arr.splice(index, 1);

  if (item.other2 === '') {

    var weFoundAnother = arr.find(function(elem, idx) {
      return elem.tenant_question_id === item.tenant_question_id &&
        elem.tenant_option_id === item.tenant_option_id &&
        elem.other2.length;
    });

    if (weFoundAnother !== undefined) {

      // We found our element and now we'll remove this too from "arr"
      // Let's get "weFoundAnother" index first using 
      //  -> arr.indexOf(weFoundAnother)
      // Then we can remove it from "arr" because it is used now.
      arr.splice(arr.indexOf(weFoundAnother), 1);

      item.other2 = weFoundAnother.other2;

    }

  }

  return item;

  // Now we'll filter the empty slots ( items that we removed )
  // And that's it

}).filter(function(i) {
  return i !== undefined
})

console.clear();
console.log(data);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>