在javascript和concat值中合并2个对象而不覆盖属性

时间:2019-01-27 03:15:11

标签: javascript ecmascript-6

我看了一堆关于此的帖子,但似乎没有一个可以做我想做的事情,或者至少没有一个是我在搜索过程中发现的。

我有两个对象,我需要将两个对象合并而不覆盖任何属性。如果两个键相同,则需要连接它们的值。 示例:

$ python3 -m cProfile -s tottime test_smp_queues3.py 
test1: building a large object and sending
BuildObject  5771.54 ms
SendObject  0.55 ms
test2: sending a bunch of small objects, lots of times
SendSmallObjects  22713.12 ms
Child process is ending
Test is finished
         33418376 function calls (33417995 primitive calls) in 29.336 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000002   15.620    0.000   15.620    0.000 {method 'acquire' of '_multiprocessing.SemLock' objects}
  4000000    2.468    0.000    5.793    0.000 random.py:174(randrange)
  4000024    2.260    0.000    3.325    0.000 random.py:224(_randbelow)
  1000002    1.883    0.000   19.981    0.000 queues.py:80(put)
  4000000    1.126    0.000    6.919    0.000 random.py:218(randint)

组合对象

const base = {
  icon: "icon--value1"
  item: "item--value"
} 

const extend = {
  icon: "icon--value2"
  item: "item--value"
  list: "list--value"
} 

我尝试使用es6 Assign和es6解构,但是它们只是覆盖了值。

const combined = { 
  icon: "icon--value1 icon--value2"
  item: "item--value"
  list: "list--value"
}

不是我追求的结果。有人知道我如何实现上述目标吗? 在此先感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

如果您乐于使用lodash(这也意味着不重新发明轮子),则可以使用here中记录的mergeWith()函数。例如:

const base = {
  icon: "icon--value1",
  item: "item--value"
} 

const extend = {
  icon: "icon--value2",
  item: "item--value",
  list: "list--value"
} 

const res = _.mergeWith(base, extend, (objVal, srcVal) => 
  objVal && objVal !== srcVal ? `${objVal} ${srcVal}` : srcVal
)

console.log(res)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>

或者,您可以通过执行以下操作来创建自己的mergeWith

const base = {
  icon: "icon--value1",
  item: "item--value"
} 

const extend = {
  icon: "icon--value2",
  item: "item--value",
  list: "list--value"
} 

const customMergeWith = (a, b, proc) => {
  const result = { ...a }
  Object.keys(b).forEach(k => {
    result[k] = proc(result[k], b[k])
  })
  return result
}

const res = customMergeWith(base, extend, (objVal, srcVal) => 
  objVal && objVal !== srcVal ? `${objVal} ${srcVal}` : srcVal
)

console.log(res)

请注意,我个人更喜欢使用lodash版本,因为它更加健壮,并且您无需担心的代码更少。如果不需要,不要尝试重新发明轮子。


最后,人们似乎认为应该避免使用lodash之类的库,这可能是因为它们的大小。但是,这些天您只能导入所需的内容。有关详细信息,请参见以下答案:How to Import a Single Lodash Function?

答案 1 :(得分:1)

您可以使用reduce来做到这一点。

这里的想法是:-

  1. 我们从两个对象的键中制作一个Set
  2. 然后我们遍历键数组。并且对于每个键,我们都在两个对象中搜索值并将它们连接起来(请记住,我们需要在此处使用||,否则,如果一个对象没有属性,则会返回undefined并将其添加到不需要的输出)。然后我们将键和值添加到输出对象。

const base = {icon: "icon--value1",item: "item--value"} 
const extend = {icon: "icon--value2",item: "item--value", list: "list--value"} 

let keys = [...new Set([...Object.keys(base), ...Object.keys(extend)]) ]

let output = keys.reduce( (op, cur) => {
  if((base[cur] && extend[cur]) && (base[cur] !== extend[cur])){
    op[cur] = (base[cur]||'') + " " + (extend[cur]||'')
  }
  else {
    op[cur] = base[cur] || extend[cur]
  }
  return op;
},{})

console.log(output)

实现Set

的目的的替代方法

const base = {icon: "icon--value1",item: "item--value"} 
    const extend = {icon: "icon--value2",item: "item--value", list: "list--value"} 

let keys = [...Object.keys(base), ...Object.keys(extend)]

let uniqueKeys = Object.keys(keys.reduce((output,cur)=>{
  if( !output[cur] ){
    output[cur]=''
  }
  return output;
},{}))

let output = uniqueKeys.reduce( (op, cur) => {
  if((base[cur] && extend[cur]) && (base[cur] !== extend[cur])){
    op[cur] = (base[cur]||'') + " " + (extend[cur]||'')
  }
  else {
    op[cur] = base[cur] || extend[cur]
  }
  return op;
},{})

console.log(output)

答案 2 :(得分:0)

对我来说,这将是最易读的处理方式...

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using FastMember;

namespace BulkCopyTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            const string filePath = "SOME FILE THAT YOU WANT TO LOAD TO A DB";

            WriteData(GetData<dynamic>(filePath));
        }

        private static void WriteData<T>(IEnumerable<T> data)
        {
            using (var bcp = new SqlBulkCopy(GetConnection(), SqlBulkCopyOptions.TableLock, null))
            using (var reader = ObjectReader.Create(data))
            {
                SetColumnMappings<T>(bcp.ColumnMappings);
                bcp.BulkCopyTimeout = 300;
                bcp.BatchSize = 150000;
                bcp.DestinationTableName = ""; //TODO: Set correct TableName
                bcp.WriteToServer(reader);
            }
        }

        private static void SetColumnMappings<T>(SqlBulkCopyColumnMappingCollection mappings)
        {
            //Setup your column mappings
        }


        private static IEnumerable<T> GetData<T>(string filePath)
        {
            using (var fileStream = File.OpenRead(filePath))
            using (var reader = new StreamReader(fileStream, Encoding.UTF8))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    //TODO: Add actual parsing logic and whatever else is needed to create an instance of T
                    yield return Activator.CreateInstance<T>();
                }
            }
        }

        private static SqlConnection GetConnection()
        {
            return new SqlConnection(new SqlConnectionStringBuilder
            {
                //TODO: Set Connection information here
            }.ConnectionString);
        }
    }
}