[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);
});

업데이트 :
교체하려는 객체에는 다음과 같은 많은 속성이 있습니다.

{id : 1, Prop1 : …, Prop2 : … 등}

해결책:

dfsq 덕분에 lodash 내에서 제대로 작동하는 것처럼 보이고 꽤 깔끔한 적절한 솔루션을 찾았 으며이 요구 사항을 여러 곳에서 보냈으므로 믹스 인에 넣었습니다. 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));

더 빠른 솔루션
@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);
    }
};



답변

귀하의 경우 배열에서 객체를 찾고 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 ));
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>


답변

가장 간단한 솔루션은 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;
});

이것은 원래 배열을 변경하지 않는 좋은 효과가 있습니다.


답변

[ES6] 이 코드는 저에게 효과적입니다.

let result = array.map(item => item.id === updatedItem.id ? updatedItem : item)


답변

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);
}

이제 모든 방법에 대한 성능을 테스트 해 보겠습니다.

코드 스 니펫 표시


답변

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);
  }


답변

시간이 지남에 따라 데이터 변이를 피하고 작은 단일 책임 기능을 작성하는보다 기능적인 접근 방식을 수용해야합니다. ECMA 스크립트 (6) 표준을 사용하면 제공과 자바 스크립트에서 함수형 프로그래밍 패러다임을 즐길 수있는 map, filterreduce방법. 다른 기본, 밑줄 또는 가장 기본적인 작업을 수행 할 다른 작업이 필요하지 않습니다.

아래에는 다른 언어 기능을 사용하여이 문제를 해결하는 방법을 보여주기 위해이 문제에 대한 제안 된 솔루션이 포함되어 있습니다.

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)


재귀 버전-매핑과 동일합니다.

파괴배열 확산이 필요합니다 .

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)


최종 배열의 순서가 중요하지 않은 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)


답변

당신은 단지 하나의 속성, lodash를 교체하려는 경우 _.find_.set충분해야한다 :

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

_.set(_.find(arr, {id: 1}), 'name', 'New Person');