基于另一个数组过滤数组并组合

时间:2019-01-02 22:36:41

标签: javascript arrays ecmascript-6

给出两个数组:

public static string ConvertDataTableToHTMLExtra(DataTable dt)
    {
        string html = "";
            html += "<table>";

            //add header row
            html += "<thead>";
            html += "<tr>";
            for (int i = 0; i < dt.Columns.Count; i++)
                html += "<td>" + dt.Columns[i].ColumnName + "</td>";
            html += "</tr>";
            html += "</thead>";

            //add rows
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                html += "<tr>";
                for (int j = 0; j < dt.Columns.Count; j++)
                    html += "<td>" + dt.Rows[i][j].ToString() + "</td>";
                html += "</tr>";
            }

            html += "</table>";

        return html;
    }

我正在尝试根据const inputOne = [ {id: "valueA", prop: 123}, {id: "valueB", prop: 456} ] const inputTwo = [ {id: "valueA", other: 54}, {id: "valueB", other: 98}, {id: "valueC", other: 11} ] 的{​​{1}}过滤inputTwo,然后合并在两者中找到的属性。

所需的输出:

inputOne

我已经尝试过idcombinedAndFiltered = [ {id: "valueA", other: 54, prop: 123}, {id: "valueB", other: 98, prop: 456} ] 和/或map的各种组合,但不知何故无法解决。

8 个答案:

答案 0 :(得分:1)

使用Map将第一个数组转换为Array.reduce(),然后缩小第二个数组,如果在Map中找到了对象,则从Map中获取对象,合并对象,然后添加到累加器:

const combine = (arr1, arr2) => {
  const arr1Map = arr1.reduce((m, o) => m.set(o.id, o), new Map)
  
  return arr2.reduce((r, o) => arr1Map.has(o.id) ? 
    [...r, { ...o, ...arr1Map.get(o.id) }] : r
  , [])
}

const inputOne = [{id: "valueA", prop: 123},{id: "valueB", prop: 456}]

const inputTwo = [{id: "valueA", other: 54},{id: "valueB", other: 98},{id: "valueC", other: 11}]

const result = combine(inputOne, inputTwo)

console.log(result)

答案 1 :(得分:1)

这应该可以解决问题(假设inputOne就像源代码一样);

const inputOne = [
 {id: "valueA", prop: 123},
 {id: "valueB", prop: 456}
]

const inputTwo = [
 {id: "valueA", other: 54},
 {id: "valueB", other: 98},
 {id: "valueC", other: 11}
]

const mergeArrays = (first, second) => {
  return first.map((firstItem) => {
    const obj = second.find((secondItem) => secondItem.id === firstItem.id);
    return {...firstItem, ...obj};
  });
};

const combinedArrays = mergeArrays(inputOne, inputTwo);

console.log(combinedArrays);

答案 2 :(得分:1)

此解决方案假定只有两个集合,并且id属性在每个集合中都是唯一的。

您可以通过以下方式基于共同属性(id)创建an intersection的两组合并对象:

  • 迭代第一组,然后在第二组中搜索第一组的当前元素。
  • 如果找到匹配项,则将两个对象合并为一个新对象,然后将该对象添加到累加器集中。
  • 退还蓄电池

此方法返回一个新集合,其中包含在两个集合中都找到的合并对象。如果任一集合中缺少对象,则该对象将不包含在输出中。

const inputOne = [ {id: "valueA", prop: 123}, {id: "valueB", prop: 456}, {id: "valueD", prop: 789} ]
const inputTwo = [ {id: "valueA", other: 54}, {id: "valueB", other: 98}, {id: "valueC", other: 11} ]

function intersectAndMerge(a, b) {
  const accumulator = []
  for(let { id, ...props } of a) {
    const match = b.find(e =>  e.id === id)
    if(match !== undefined) {
      accumulator.push({ ...match, ...props })
    }
  }
  return accumulator
}

console.log(intersectAndMerge(inputOne, inputTwo))

这也可以通过reduce循环来完成,但是我发现它的可读性较差:

const inputOne = [ {id: "valueA", prop: 123}, {id: "valueB", prop: 456}, {id: "valueD", prop: 789} ]
const inputTwo = [ {id: "valueA", other: 54}, {id: "valueB", other: 98}, {id: "valueC", other: 11} ]

function intersectAndMerge(a, b) {
  return a.reduce((accumulator, { id, ...props }) => {
    const match = b.find(e =>  e.id === id)
    if(match !== undefined) {
      accumulator.push({ ...match, ...props })
    }
    return accumulator
  }, [])
}

console.log(intersectAndMerge(inputOne, inputTwo))

答案 3 :(得分:0)

inputOne.map((a, i) => ({...a, ...inputTwo[i]}))

它假设inputOne是较短的那个,您可以使用if来确保在所有情况下都是正确的。

编辑: 在真正的功能问题上,人们可能会在haskell中使用zip之类的东西,但是恐怕如果没有进一步的库或自己实现它,恐怕就会陷入类似的情况。

编辑2:

inputOne.map((a, i) => ({...a, ...(inputTwo.filter(x => x.id === a.id)[0])}))

此功能基于id属性,但阅读效果不够好。

答案 4 :(得分:0)

使用for的简单解决方案:

// declare an empty array:
let resArr = []

for(i=0; i<inputOne.length; i++) {
  for(j=0; j<inputTwo.length; j++) {
    if(inputOne[i].id === inputTwo[j].id) {
      resArr.push({ ...inputOne[i], ...inputTwo[j] })
    }
  }
}

答案 5 :(得分:0)

您可以使用地图和过滤器解决此问题。如果我对您想要的内容没有错,这可能会有所帮助

let result = inputOne.map((item) => {
    let leftItems = inputTwo.filter((item2) => {
        return item2.id == item.id
    }) 
    if(leftItems.length > 0) {
        return {id: item.id, other: leftItems[0].other, prop: item.prop}
        // or return {...item, ...leftItems[0]}
    }
}).filter(item => !! item)

答案 6 :(得分:0)

好吧,您可以首先构建一个Object并使用它获取其他值,同时使用.map遍历另一个数组

const inputOne = [
 {id: "valueA", prop: 123},
 {id: "valueB", prop: 456}
],
 inputTwo = [
 {id: "valueA", other: 54},
 {id: "valueB", other: 98},
 {id: "valueC", other: 11}
],
ids = {};

inputTwo.forEach(function (o) {
    ids[o.id] = o;
});

var res = inputOne.map(function (o) {
    return {
        other: ids[o.id].other,
        prop: o.prop,
        id: o.id
    };
});

console.log(res)

答案 7 :(得分:0)

我认为几乎所有解决方案都将进行某种形式的双重迭代,无论是通过for循环,映射还是过滤器。与上面列出的方法不同的另一种方法是使用像lodash这样的库。 This answer already gives a pretty good example of the unionBy function