在lodash中有一个函数来替换匹配的项目

Vis*_*eth 113 javascript lodash

我想知道在lodash中是否有一个更简单的方法来替换JavaScript集合中的项目?(可能重复,但我不明白那里的答案:)

我看了他们的文档但找不到任何东西

我的代码是:

var arr = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];
// Can following code be reduced to something like _.XX(arr, {id:1}, {id:1, name: "New Name"});
_.each(arr, function(a, idx){
  if(a.id === 1){
    arr[idx] = {id:1, name: "Person New Name"};
    return false;
  }
});

_.each(arr, function(a){
  document.write(a.name);
});
Run Code Online (Sandbox Code Playgroud)

更新: 我正在尝试替换的对象有许多属性,如

{id:1,Prop1:...,Prop2:...,依此类推}

解:

感谢dfsq,但我在lodash中找到了一个合适的解决方案,似乎工作正常并且非常整洁,我把它放在mixin中,因为我在很多地方都有这个要求.JSBin

var update = function(arr, key, newval) {
  var match = _.find(arr, key);
  if(match)
    _.merge(match, newval);
  else
    arr.push(newval);    
};

_.mixin({ '$update': update });

var arr = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];

_.$update(arr, {id:1}, {id:1, name: "New Val"});


document.write(JSON.stringify(arr));
Run Code Online (Sandbox Code Playgroud)

更快的解决方案 正如@dfsq所指出的,以下方法更快

var upsert = function (arr, key, newval) {
    var match = _.find(arr, key);
    if(match){
        var index = _.indexOf(arr, _.find(arr, key));
        arr.splice(index, 1, newval);
    } else {
        arr.push(newval);
    }
};
Run Code Online (Sandbox Code Playgroud)

dfs*_*fsq 170

在您的情况下,您需要做的就是在数组中查找对象并使用Array.prototype.splice方法:

var arr = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];

// Find item index using _.findIndex (thanks @AJ Richardson for comment)
var index = _.findIndex(arr, {id: 1});

// Replace item at index using native splice
arr.splice(index, 1, {id: 100, name: 'New object.'});

// "console.log" result
document.write(JSON.stringify( arr ));
Run Code Online (Sandbox Code Playgroud)
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

  • 为什么不使用`_.findIndex`?那你就不需要使用`_.indexOf`. (13认同)

小智 26

似乎最简单的解决方案是使用ES6 .map或lodash _.map:

var arr = [{id: 1, name: "Person 1"}, {id: 2, name: "Person 2"}];

// lodash
var newArr = _.map(arr, function(a) {
  return a.id === 1 ? {id: 1, name: "Person New Name"} : a;
});

// ES6
var newArr = arr.map(function(a) {
  return a.id === 1 ? {id: 1, name: "Person New Name"} : a;
});
Run Code Online (Sandbox Code Playgroud)

这具有避免改变原始数组的良好效果.

  • 但是你每次都要创建一个新阵列......值得注意的是. (6认同)
  • 不过,不创建新数组的唯一选择是改变现有数组。此外,创建新阵列可能不会对性能产生影响。从我点赞。 (6认同)

evi*_*ive 21

function findAndReplace(arr, find, replace) {
  let i;
  for(i=0; i < arr.length && arr[i].id != find.id; i++) {}
  i < arr.length ? arr[i] = replace : arr.push(replace);
}
Run Code Online (Sandbox Code Playgroud)

现在让我们测试所有方法的性能:

// TC's first approach
function first(arr, a, b) {
  _.each(arr, function (x, idx) {
    if (x.id === a.id) {
      arr[idx] = b;
      return false;
    }
  });
}

// solution with merge
function second(arr, a, b) {
  const match = _.find(arr, a);
  if (match) {
    _.merge(match, b);
  } else {
    arr.push(b);
  }
}

// most voted solution
function third(arr, a, b) {
  const match = _.find(arr, a);
  if (match) {
    var index = _.indexOf(arr, _.find(arr, a));
    arr.splice(index, 1, b);
  } else {
    arr.push(b);
  }
}

// my approach
function fourth(arr, a, b){
  let l;
  for(l=0; l < arr.length && arr[l].id != a.id; l++) {}
  l < arr.length ? arr[l] = b : arr.push(b);
}

function test(fn, times, el) {
  const arr = [], size = 250;
  for (let i = 0; i < size; i++) {
    arr[i] = {id: i, name: `name_${i}`, test: "test"};
  }

  let start = Date.now();
  _.times(times, () => {
    const id = Math.round(Math.random() * size);
    const a = {id};
    const b = {id, name: `${id}_name`};
    fn(arr, a, b);
  });
  el.innerHTML = Date.now() - start;
}

test(first, 1e5, document.getElementById("first"));
test(second, 1e5, document.getElementById("second"));
test(third, 1e5, document.getElementById("third"));
test(fourth, 1e5, document.getElementById("fourth"));
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<div>
  <ol>
    <li><b id="first"></b> ms [TC's first approach]</li>
    <li><b id="second"></b> ms [solution with merge]</li>
    <li><b id="third"></b> ms [most voted solution]</li>
    <li><b id="fourth"></b> ms [my approach]</li>
  </ol>
<div>
Run Code Online (Sandbox Code Playgroud)

  • 由于对人不感兴趣("这是一种某种笑话")而导致他们失去学习能力.想象一下,如果我以"做一个聪明的人,我希望你不要对你的情绪懒惰,并考虑到这一点"来完成这个. (4认同)
  • 我不想伤害任何人,但我想知道比最初的主题创作者的方法更糟糕的解决方案得到了如此多的选票.那些为此投票的人有什么规则?而且我沮丧的是,人们盲目地信任最投票的答案而没有批判性的思考. (4认同)
  • 值得注意的是,您的解决方案和 TC 的解决方案仅按 ID 进行过滤。这是这两个运行速度更快的第一个原因。另外两个允许您传递过滤所需的对象的任何部分,这可能更适合作为 upsert 函数。 (2认同)

小智 19

[ES6]此代码适用于我.

let result = array.map(item => item.id === updatedItem.id ? updatedItem : item)
Run Code Online (Sandbox Code Playgroud)


JVi*_*ela 9

您还可以使用findIndex和pick来实现相同的结果:

  var arr  = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];
  var data = {id: 2, name: 'Person 2 (updated)'};
  var index = _.findIndex(arr, _.pick(data, 'id'));
  if( index !== -1) {
    arr.splice(index, 1, data);
  } else {
    arr.push(data);
  }
Run Code Online (Sandbox Code Playgroud)


小智 8

如果你只是想更换一个属性,lodash_.find_.set应该足够:

var arr = [{id: 1, name: "Person 1"}, {id: 2, name: "Person 2"}];

_.set(_.find(arr, {id: 1}), 'name', 'New Person');
Run Code Online (Sandbox Code Playgroud)


Prz*_*ski 6

随着时间的流逝,您应该采用一种更具功能性的方法,在这种方法中,您应该避免数据突变并编写小的,单一责任的函数。与ECMAScript 6个标准,你可以在JavaScript中享受函数式编程范式与所提供的mapfilterreduce方法。您不需要其他破折号,下划线或其他可以执行大多数基本操作的内容。

下面,我提供了一些针对此问题的建议解决方案,以展示如何使用不同的语言功能来解决此问题:

使用ES6地图:

const replace = predicate => replacement => element =>
  predicate(element) ? replacement : element
 
const arr = [ { id: 1, name: "Person 1" }, { id:2, name:"Person 2" } ];
const predicate = element => element.id === 1
const replacement = { id: 100, name: 'New object.' }

const result = arr.map(replace (predicate) (replacement))
console.log(result)
Run Code Online (Sandbox Code Playgroud)


递归版本-等效的映射:

需要解构数组扩展

const replace = predicate => replacement =>
{
  const traverse = ([head, ...tail]) =>
    head
    ? [predicate(head) ? replacement : head, ...tail]
    : []
  return traverse
}
 
const arr = [ { id: 1, name: "Person 1" }, { id:2, name:"Person 2" } ];
const predicate = element => element.id === 1
const replacement = { id: 100, name: 'New object.' }

const result = replace (predicate) (replacement) (arr)
console.log(result)
Run Code Online (Sandbox Code Playgroud)


当最终数组的顺序不重要时,可以将其object用作HashMap数据结构。如果您已经将键集合用作,则非常方便object-否则,您必须先更改表示形式。

需要对象剩余散布计算的属性名称Object.entries

const replace = key => ({id, ...values}) => hashMap =>
({
  ...hashMap,       //original HashMap
  [key]: undefined, //delete the replaced value
  [id]: values      //assign replacement
})

// HashMap <-> array conversion
const toHashMapById = array =>
  array.reduce(
    (acc, { id, ...values }) => 
    ({ ...acc, [id]: values })
  , {})
  
const toArrayById = hashMap =>
  Object.entries(hashMap)
  .filter( // filter out undefined values
    ([_, value]) => value 
  ) 
  .map(
    ([id, values]) => ({ id, ...values })
  )

const arr = [ { id: 1, name: "Person 1" }, { id:2, name:"Person 2" } ];
const replaceKey = 1
const replacement = { id: 100, name: 'New object.' }

// Create a HashMap from the array, treating id properties as keys
const hashMap = toHashMapById(arr)
console.log(hashMap)

// Result of replacement - notice an undefined value for replaced key
const resultHashMap = replace (replaceKey) (replacement) (hashMap)
console.log(resultHashMap)

// Final result of conversion from the HashMap to an array
const result = toArrayById (resultHashMap)
console.log(result)
Run Code Online (Sandbox Code Playgroud)


rmm*_*ann 5

也遇到了这个,并简单地这样做了。

const persons = [{id: 1, name: "Person 1"}, {id:2, name:"Person 2"}];
const updatedPerson = {id: 1, name: "new Person Name"}
const updatedPersons = persons.map(person => (
  person.id === updated.id
    ? updatedPerson
    : person
))
Run Code Online (Sandbox Code Playgroud)

如果需要的话我们可以概括它

const replaceWhere = (list, predicate, replacement) => {
  return list.map(item => predicate(item) ? replacement : item)
}

replaceWhere(persons, person => person.id === updatedPerson.id, updatedPerson)
Run Code Online (Sandbox Code Playgroud)