【问题标题】:How to merge uniquely two JSON files?如何唯一地合并两个 JSON 文件?
【发布时间】:2018-03-29 06:07:24
【问题描述】:

我想合并两个包含电影信息的 JSON 文件。这些文件有一些共同点。我想编写第三个文件,其中包含所有电影而不重复它们。

这是我目前所拥有的:

const fs = require('fs');
const path = require('path');

const readMovies1 = () => {
  return new Promise((resolve, reject) => {
    fs.readFile(path.join(__dirname,'../models/movies.json'), 'utf8', (err, data1) => {
      if(err) reject(err);
      let data = JSON.parse(data1);
      resolve(data);
    });
  });
};

const readMovies2 = (data1) => {
  return new Promise((resolve, reject) =>{
    fs.readFile(path.join(__dirname,'../models/movies2.json'), 'utf8', (err, data) => {
      if(err) reject(err);
      data = JSON.parse(data);
      resolve([data1,data]);
    });
  });
};

const merging = (data1, data2) => {
   var args = arguments;
   var hash = {};
   var arr = [];
   for (var i = 0; i < args.length; i++) {
      for (var j = 0; j < args[i].length; j++) {
        if (hash[args[i][j]] !== true) {
          arr[arr.length] = args[i][j];
          hash[args[i][j]] = true;
        }
      }
    }
return arr;

};
readMovies1()
  .then(readMovies2)
    .catch((err) => console.error(err))
  .then((data) => console.log(merging(data[0],data[1])))
    .catch((err) => console.error(err));

但是控制台输出给了我这个:

  [ undefined,
  '/',
  'U',
  's',
  'e',
  'r',
  'g',
  'o',
  'n',
  'z',
  'P',
  'j',
  'c',
  't',
  'J',
  'S',
  'a',
  'd',
  'm',
  '-',
  'v',
  'i',
  'l',
  'b',
  '.' ]

我在这里的堆栈溢出问题中找到了合并函数,但它正在合并一个数字数组,我正在合并对象数组。我不知道这是否与我的问题有关。

这是我的一个源文件(另一个遵循相同的模式,但有一些其他电影):

[{
  "title": "Spider-Man: Homecoming",
  "usersScore": "92%",
  "criticsScore": "89%"
}, {
  "title": "Girls Trip",
  "usersScore": "89%",
  "criticsScore": "83%"
}, {
  "title": "Captain Underpants: The First Epic Movie (Captain Underpants)",
  "usersScore": "87%",
  "criticsScore": "62%"
}, {
  "title": "Guardians of the Galaxy Vol. 2",
  "usersScore": "82%",
  "criticsScore": "88%"
}, {
  "title": "Wonder Woman",
  "usersScore": "92%",
  "criticsScore": "89%"
}, {
  "title": "First They Killed My Father",
  "usersScore": "88%",
  "criticsScore": "83%"
}, {
  "title": "Baby Driver",
  "usersScore": "93%",
  "criticsScore": "87%"
}, {
  "title": "Demon",
  "usersScore": "91%",
  "criticsScore": "56%"
}, {
  "title": "The Music of Strangers: Yo-Yo Ma and the Silk Road Ensemble",
  "usersScore": "84%",
  "criticsScore": "85%"
}, {
  "title": "Colossal",
  "usersScore": "80%",
  "criticsScore": "59%"
}, {
  "title": "Certain Women",
  "usersScore": "92%",
  "criticsScore": "51%"
}, {
  "title": "Godzilla Resurgence (Shin Godzilla)",
  "usersScore": "84%",
  "criticsScore": "73%"
}, {
  "title": "My Cousin Rachel",
  "usersScore": "76%",
  "criticsScore": "47%"
}, {
  "title": "The Meyerowitz Stories (New and Selected)",
  "usersScore": "93%",
  "criticsScore": "84%"
}, {
  "title": "Raw",
  "usersScore": "90%",
  "criticsScore": "77%"
}, {
  "title": "The Wedding Plan",
  "usersScore": "86%",
  "criticsScore": "65%"
}, {
  "title": "Maudie",
  "usersScore": "88%",
  "criticsScore": "92%"
}, {
  "title": "Heal the Living (Réparer les vivants)",
  "usersScore": "90%",
  "criticsScore": "70%"
}, {
  "title": "Lady Macbeth",
  "usersScore": "89%",
  "criticsScore": "72%"
}, {
  "title": "The Exception (The Kaiser's Last Kiss)",
  "usersScore": "76%",
  "criticsScore": "67%"
}, {
  "title": "Citizen Jane: Battle for the City",
  "usersScore": "94%",
  "criticsScore": "61%"
}, {
  "title": "The Beguiled",
  "usersScore": "78%",
  "criticsScore": "50%"
}, {
  "title": "The Big Sick",
  "usersScore": "98%",
  "criticsScore": "89%"
}, {
  "title": "The Little Hours",
  "usersScore": "77%",
  "criticsScore": "53%"
}, {
  "title": "A Ghost Story",
  "usersScore": "91%",
  "criticsScore": "66%"
}, {
  "title": "The Hero",
  "usersScore": "77%",
  "criticsScore": "64%"
}, {
  "title": "Megan Leavey",
  "usersScore": "84%",
  "criticsScore": "83%"
}, {
  "title": "Band Aid",
  "usersScore": "85%",
  "criticsScore": "73%"
}, {
  "title": "It Comes At Night",
  "usersScore": "89%",
  "criticsScore": "43%"
}, {
  "title": "The Midwife (Sage femme)",
  "usersScore": "86%",
  "criticsScore": "82%"
}, {
  "title": "Brawl in Cell Block 99",
  "usersScore": "93%",
  "criticsScore": "75%"
}, {
  "title": "Gerald's Game",
  "usersScore": "89%",
  "criticsScore": "78%"
}]

【问题讨论】:

  • 您的源数据是什么样的?
  • 一种更简单的思考方式是连接两个数组,然后只过滤掉唯一的(或有时称为不同的)值。合并通常被理解为一个不同的问题,并且比仅仅选择独特的属性要复杂得多。搜索“合并”将产生与您的案例几乎不相关的结果。
  • @BCartolo OP 想要“合并”数组,而不是对象。
  • @AndrewLohr OP 想要“合并”数组,而不是对象。此外,Object.assign 并没有真正合并,它只会覆盖属性并且它的工作很浅,即仅在顶层。任何深度嵌套的值都不会正确合并。如果打算合并对象,则必须为深度嵌套的对象实现自定义处理或使用执行此操作的库,例如lodash.merge.

标签: javascript arrays json node.js merge


【解决方案1】:

您真正需要的是合并两个数组,然后过滤它们以删除重复项:

const merge = (data1, data2) => {
    // keeps track of already existing titles to avoid duplicates
    let existingIndexes = {};

    // check the the arguments to make sure the code does not break
    data1 = data1 instanceof Array ? data1 : [];
    data2 = data2 instanceof Array ? data2 : [];

    // return a concatenated and filtered copy result
    return data1.concat(data2).filter((movie) => {
        if (existingIndexes.hasOwnProperty(movie.title)) {
            existingIndexes[movie.title] = true;
            return true;
        }
        return false;
    });
};

【讨论】:

  • 而不是existingIndexes = [],使用existingIndexes = {} - 对象键查找比在数组上调用.indexOf() 更有效。
  • 是的,我同意,但如果我使用对象,我不仅需要添加一个键,还需要添加一个值,当然它可以是一个简单的布尔值,但这个看起来更干净。跨度>
  • .filter(movie =&gt; index.hasOwnProperty(movie.title) || index[movie.title] = true); :) -- 诚然,这可能不是我在生产代码中使用的东西。
  • 是的。它也有一个错误。应该是!index.hasOwnProperty(movie.title)。看到来不及更正了,现在评论被锁定了。我也觉得太难读了。我会使用这个的变体和适当的if
  • 当然,绝对运行时间与数据大小有关。有几百个数组条目,这并不重要。但是,indexOf() 仍然是 O(n)hasOwnProperty() 实际上是 O(1)。需要牢记这一点 - 以及我喜欢使用对象来处理这类事情的原因 - 从来没有错。
【解决方案2】:

我最喜欢处理从数组中删除重复项的方法是将对象用作字典,然后再转换回数组。这不是最有效的方法,但我喜欢代码的简单性。我们需要一些方法来按键跟踪重复值(在本例中是您的电影标题),而 Objects 可以轻松地为我们处理这个问题。

const merge = (key, arr1, arr2) => {
    // Should probably check our parameters, but I'm leaving it out
    // Our "dictionary" that will help prevent duplicates by using keys
    let dictionary = {};

    // Values in arr2 will overwrite values in arr1 if there is a duplicate
    arr1.concat(arr2).forEach(item => {
        dictionary[item[key]] = item;
        // To always keep the first value, you could replace the previous line with this:
        // dictionary[item[key]] = dictionary[item[key]] || item;
    });

    return Object.keys(dictionary).map(i => dictionary[i]);
};

【讨论】:

    【解决方案3】:

    类似的东西应该可以。

    const getTitles = movies => movies.map(movie => movie.title);
    const merge = (data1, data2) => {
            const titles1 = getTitles(data1);
            return data1.concat(data2.filter(movie => !titles1.includes(movie.title)));
        }
    

    【讨论】:

      【解决方案4】:

      您可以使用array#reduce 在您的两个数组中获取独特的电影。

      var data1 = [{"title":"Spider-Man: Homecoming","usersScore":"92%","criticsScore":"89%"},{"title":"Girls Trip","usersScore":"89%","criticsScore":"83%"},{"title":"Captain Underpants: The First Epic Movie (Captain Underpants)","usersScore":"87%","criticsScore":"62%"},{"title":"Guardians of the Galaxy Vol. 2","usersScore":"82%","criticsScore":"88%"},{"title":"Wonder Woman","usersScore":"92%","criticsScore":"89%"},{"title":"First They Killed My Father","usersScore":"88%","criticsScore":"83%"},{"title":"Baby Driver","usersScore":"93%","criticsScore":"87%"},{"title":"Demon","usersScore":"91%","criticsScore":"56%"},{"title":"The Music of Strangers: Yo-Yo Ma and the Silk Road Ensemble","usersScore":"84%","criticsScore":"85%"},{"title":"Colossal","usersScore":"80%","criticsScore":"59%"},{"title":"Certain Women","usersScore":"92%","criticsScore":"51%"},{"title":"Godzilla Resurgence (Shin Godzilla)","usersScore":"84%","criticsScore":"73%"},{"title":"My Cousin Rachel","usersScore":"76%","criticsScore":"47%"},{"title":"The Meyerowitz Stories (New and Selected)","usersScore":"93%","criticsScore":"84%"},{"title":"Raw","usersScore":"90%","criticsScore":"77%"},{"title":"The Wedding Plan","usersScore":"86%","criticsScore":"65%"},{"title":"Maudie","usersScore":"88%","criticsScore":"92%"},{"title":"Heal the Living (Réparer les vivants)","usersScore":"90%","criticsScore":"70%"},{"title":"Lady Macbeth","usersScore":"89%","criticsScore":"72%"},{"title":"The Exception (The Kaiser's Last Kiss)","usersScore":"76%","criticsScore":"67%"},{"title":"Citizen Jane: Battle for the City","usersScore":"94%","criticsScore":"61%"},{"title":"The Beguiled","usersScore":"78%","criticsScore":"50%"},{"title":"The Big Sick","usersScore":"98%","criticsScore":"89%"},{"title":"The Little Hours","usersScore":"77%","criticsScore":"53%"},{"title":"A Ghost Story","usersScore":"91%","criticsScore":"66%"},{"title":"The Hero","usersScore":"77%","criticsScore":"64%"},{"title":"Megan Leavey","usersScore":"84%","criticsScore":"83%"},{"title":"Band Aid","usersScore":"85%","criticsScore":"73%"},{"title":"It Comes At Night","usersScore":"89%","criticsScore":"43%"},{"title":"The Midwife (Sage femme)","usersScore":"86%","criticsScore":"82%"},{"title":"Brawl in Cell Block 99","usersScore":"93%","criticsScore":"75%"},{"title":"Gerald's Game","usersScore":"89%","criticsScore":"78%"}],
          data2 = [{ "title": "The Midwife (Sage femme)","usersScore": "86%","criticsScore": "82%"}, {"title": "Brawl in Cell Block 99","usersScore": "93%", "criticsScore": "75%"}, {"title": "Gerald's Game","usersScore": "89%","criticsScore": "78%" }];
      
      const merging = (data1, data2) => {
         let unique = data1.concat(data2).reduce((map, movie) => {
            return map[movie.title] = movie, map;
         }, Object.create(null));
         return Object.values(unique);
      };
      console.log(merging(data1,data2));
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-17
        • 1970-01-01
        • 1970-01-01
        • 2022-07-05
        • 2021-08-13
        • 1970-01-01
        • 1970-01-01
        • 2017-12-28
        相关资源
        最近更新 更多