如何在功能样式中只更改对象数组中的一个特定对象?

时间:2014-01-21 14:19:45

标签: javascript functional-programming underscore.js code-readability

让我们假设我们想要创建一些非常易读的代码来执行下一步:

  1. 遍历列表
  2. 的所有元素
  3. 除了只有一个特定元素(即使多个元素可以满足搜索条件)时,它们都会平等地更改所有元素。
  4. 使用更改的元素返回此列表
  5. 使用_.underscore power
  6. 例如,我想将isChosen的{​​{1}}属性仅添加到具有true属性的第一个元素,其他元素应该为此新增hasRoom个值财产false

    以下是使用_.underscore lib:

    创建的代码
    hasRoom

    此代码有效,但我认为可以有更好的方法制作相同的方法,也许使用_.chain()?

    所以,作为输入,我们可以

      var i = 0
      var changedList = []
      _.each(list, function(el) {
        if (el.hasRoom && i === 0) {
          _.extend(el, { isChosen: true })
          i++
        } else {
          _.extend(el, { isChosen: false })
        }
        changedList.push(el)
      })
    

    结果我们应该得到

    [
        {hasRoom: false}, 
        {hasRoom: true}, 
        {hasRoom: true}
    ]
    

5 个答案:

答案 0 :(得分:2)

var _ = require("underscore");
var data = [{hasRoom: true}, {hasRoom: true}, {}], found = false;

_.each(data, function(currentObject) {
    _.defaults(currentObject, {isChosen: false});
    if (found === false && currentObject.hasRoom) {
        found = currentObject.isChosen = true;
    }
});

console.log(data);

<强>输出

[ { hasRoom: true, isChosen: true },
  { hasRoom: true, isChosen: false },
  { isChosen: false } ]

答案 1 :(得分:1)

您可以使用通常称为first的方法来查找符合条件的第一个元素:

function first (array, filter_function) {
    var index, len = array.length;
    for (index = 0; index < len; index += 1) {
        if (filter_function(array[index], index)) {
            return index;
        }
    }
    return -1;
}

rooms = [
    { hasRoom: false }, 
    { hasRoom: true }, 
    { hasRoom: true }
];

free_room = first(rooms, function (room) {
    return room.hasRoom;
});
if (free_room === -1) {
    throw "Dilbert lied!";
}
rooms[free_room].isChosen = true;

请注意,_js还在数组上定义了first函数,但对于cathead函数则更多。你可以争论语义。

答案 2 :(得分:1)

在功能样式中,您可以这样做:

// type: [a] -> (a -> Bool -> b) -> (a -> Bool) -> [b]
function changeFirstinList(list, change, predicate) {
    var first = true;
    return _.map(list, function(el) {
        return change(el, first && !(first = !predicate(el)));
    });
}

changeFirstinList([
    {hasRoom: false}, 
    {hasRoom: true}, 
    {hasRoom: true}
], function(el, isFirstwithpred) {
    return {hasRoom: el.hasRoom, isChosen: isFirstwithpred};
}, function(el) {
    return el.hasRoom;
});

答案 3 :(得分:1)

此解决方案修改了设置isChosen的函数:

function notChosen(place){
  return false;
}

function chosen(place){
  if( !place.hasRoom ) return notChosen(place);
  setChosen = notChosen;
  return true;
}

var setChosen = chosen;

_.each(places, function(place){
    place.isChosen = setChosen(place);
});

只有找到有房间的第一个地方才会执行if语句。

答案 4 :(得分:0)

最后我的代码开始看起来像这样:

function addChosenPropertyToFirstElementWithRooms(hotels) {
  var found = false
  return _.map(list, function(el) {
    return _.merge(el, { isChosen: isFirstElementWithRooms(el) })
  })

  function isFirstHotelWithRooms(el) {
    return found ? false : found = el.hasRoom
  }
}

功能的使用很容易

var changedList = addChosenPropertyToFirstElementWithRooms(originalList)