对象数组与Lodash的深度对比

问题描述 投票:0回答:4

我有一个系统,我想在用户执行某些操作时向他们显示有用的消息。但是,根据用户的不同,如果我们知道他们已经熟悉特定操作,我们可能会选择不显示消息。

我有两个多维数组,我需要比较它们以确定是否应该显示消息。一个包含用户分类,一个包含所有消息。

我的问题是,编码风格在可能的情况下更喜欢使用 Lodash 助手,而我不太精通它。

下面的代码做了我想要的,但它显然不漂亮或性能不佳。

// user classification for each type of action     
const classifications = [
  {
    status: 'basic',
    actionTypes: [
      'copy', 'paste'
    ],
  },
  {
    status: 'basic',
    actionTypes: [
      'buy', 'sell'
    ],
  },
  {
    status: 'professional',
    actionTypes: [
      'drag', 'drop'
    ],
  }
];

// array of messages for each set of actions
const messages = [
  {
    message: 'foo',
    actionTypes: [
      'copy', 'paste'
    ],
  },
  {
    message: 'bar',
    actionTypes: [
      'buy', 'sell'
    ],
  },
  {
    message: 'baz',
    actionTypes: [
      'drag', 'drop'
    ],
  }
];

// returns only messages for which the user is not professional
function getMappedMessages() {

  const basicClassifications = _.filter(classifications, ['status', 'basic']);
  const filteredMessages = [];  

  for (let i = 0; i < basicClassifications.length; i++) {
    for (let j = 0; j < basicClassifications[i].actionTypes.length; j++) {
      for (let k = 0; k < messages.length; k++) {
         if (_.includes(messages[k].actionTypes, basicClassifications[i].actionTypes[j])) {
           filteredMessages.push(messages[k]);
           break;
         }
      }      
    }
  }

  return filteredMessages;
}


console.log(getMappedMessages());
<script src="https://cdn.jsdelivr.net/lodash/4/lodash.min.js"></script>

也可在 JSBin 上获得

如您所见,每组操作(例如“复制”和“粘贴”)都有一条消息,并且用户有一个相应的操作集和一个分类。如果分类不专业,我匹配两个内部数组(对于外部数组中的每个对象),并返回仅包含“基本”消息的对象。

这两个数组很可能是相同的(所以我可以直接比较,也许用

_.difference
?),但我不确定。

如何使这个怪物更具可读性和性能?我应该做一些扁平化吗?

数据来自两个独立的端点,我无法修改结构。

javascript arrays multidimensional-array lodash
4个回答
4
投票

_.isEqual()
会做你想做的事。

至于清理它,我建议要么把它展平和/或把它分解成函数,这样你至少可以更好地理解发生了什么。


1
投票

您可以使用

actionTypes
lodash#keyBy
作为键索引所有分类。使用索引分类作为使用
lodash#filter
保留不属于
professional
状态的消息的方法。

// index all classifications by their actionTypes
var indexes = _.keyBy(classifications, 'actionTypes');

// get all non-profiessional messages
var nonProMessages = _.filter(messages, function(message) {
  // path to get the status matching the 
  // actionType of this message
  var key = [message.actionTypes, 'status'];
  // compare the status represented by the message
  return _.get(indexes, key) !== 'professional';
});

// user classification for each type of action     
const classifications = [{
    status: 'basic',
    actionTypes: [
      'copy', 'paste'
    ],
  },
  {
    status: 'basic',
    actionTypes: [
      'buy', 'sell'
    ],
  },
  {
    status: 'professional',
    actionTypes: [
      'drag', 'drop'
    ],
  }
];

// array of messages for each set of actions
const messages = [{
    message: 'foo',
    actionTypes: [
      'copy', 'paste'
    ],
  },
  {
    message: 'bar',
    actionTypes: [
      'buy', 'sell'
    ],
  },
  {
    message: 'baz',
    actionTypes: [
      'drag', 'drop'
    ],
  }
];

// index all classifications by their actionTypes
var indexes = _.keyBy(classifications, 'actionTypes');

// get all non-profiessional messages
var nonProMessages = _.filter(messages, function(message) {
  // path to get the status matching the 
  // actionType of this message
  var key = [message.actionTypes, 'status'];
  // compare the status represented by the message
  return _.get(indexes, key) !== 'professional';
});

console.log(nonProMessages);
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>


1
投票

有很多方法可以改进代码。我做的第一件事是执行过滤、映射、缩减。

  • filter:将数组缩短为仅包含我们需要的元素
  • map:将数组中的每个对象转换为只有 ActionTypes
  • reduce:将所有 ActionType 连接成一个数组

const classifications = [{
    status: 'basic',
    actionTypes: [ 'copy', 'paste'],
  },
  {
    status: 'basic',
    actionTypes: [ 'buy', 'sell' ],
  },
  {
    status: 'professional',
    actionTypes: [ 'drag', 'drop' ],
  }
];

const messages = [{
    message: 'foo',
    actionTypes: [ 'copy', 'paste' ],
  },
  {
    message: 'bar',
    actionTypes: ['buy', 'sell'],
  },
  {
    message: 'baz',
    actionTypes: [ 'drag', 'drop' ],
  }
];

function getBasicActionTypes() {
  return classifications
    .filter(c => c.status === 'basic')
    .map(c => c.actionTypes)
    .reduce((a,b) => a.concat(b), []);
}

function getMessages(actionTypes) {
  return messages
  .filter(m => m.actionTypes.some(a => actionTypes.indexOf(a) > -1));
}

function getMessagesFromSet(actionTypeSet) {
  return messages
  .filter(m => m.actionTypes.some(a => actionTypeSet.has(a)));
}

const arr = getBasicActionTypes();
const m1 = getMessages(arr);
const s = new Set(arr);
const m2 = getMessagesFromSet(s);

console.log(m2);
<script src="https://cdn.jsdelivr.net/lodash/4/lodash.min.js"></script>

我必须举例结果数组,

m1
m2
都包含相同的元素。不同之处在于
m2
是从 ES6 Set 派生的,但应该更快。


1
投票

当然,其中大部分都可以在纯 ES6/ES7 中实现。但是你问的是

lodash
,所以这里有一些惯用的
lodash

链接真的很酷,因为它基本上为您提供了价值的包装器,这就是为什么在使用

value()
时必须在最后调用
chain()
的原因。

它允许你按顺序链接任何你想要的

lodash
函数,你不受输出是数组或对象等的限制

const getMappedMessages = (classifications, messages) => {
  const classActionsMap =  _.chain(classifications)
    .filter(['status', 'basic'])
    .map(_.get('actionTypes')))
    .reduce((prev, curr) => { 
      const key = JSON.stringify(curr);
      Object.assign(prev, {[key]: true}) 
    }, {})
    .value();

   return _.filter(messages, msg => classActionsMap[msg.actionTypes]);
 }
© www.soinside.com 2019 - 2024. All rights reserved.