我想尽快匹配来自流的请求

时间:2017-05-11 23:39:35

标签: javascript arrays performance stream javascript-objects

我正在使用Map来匹配传入的请求。我希望在得到它们后立即将这些请求与他们的对匹配。订单很重要,因为它是第一个来,首先匹配。避免不必要的操作是必需的。我的理解是哈希映射比数组迭代更快,而映射维护顺序。匹配流对象的最佳实现是什么,几乎没有空间或时间复杂度?数据结构不是一成不变的,只要信息不丢失,它就可以以任何优化的格式进行修改和编码。根据我的理解,可以实现的最好的是O(n)。我面临的另一个问题是散列是覆盖队列中的重复项。这就是我所拥有的。

function* match(items, identity, remaining = new Map()) { 
  for (let item of items) {
   let id = identity(item);
   let pair = x =>({type:x.type==="passenger"? "driver": "passenger", direction:x.direction,          time:x.time})
    let  key = item=> item.type + item.direction + item.time;
    let candidate = remaining.get(key(pair(id)));
    if (candidate) {
      remaining.delete(key(pair(id)));
      yield [item, candidate];
    } else {
      remaining.set(key(id), item);
    }
  }
}
// Example:
let items = [{
    type: 'driver',
    direction: 'east',
    time: '9:15',
    name:['Archibald Trump']
  },{ 
    type: 'passenger',
    direction: 'east',
    time: '9:15',
    name:['Bacon Eater']
  },{ 
    type: 'passenger',
    direction: 'east',
    time: '9:15',
    name:['Banjo Barney']
  },{ 
    type: 'passenger',
    direction: 'east',
    time: '9:15',
    name:['Flimsy Stick']
  }, {
    type: 'passenger',
    direction: 'west',
    time: '9:30',
    name:['Big Red']
  },{
    type: 'passenger',
    direction: 'west',
    time: '9:35',
    name:['Hathaway Anne']
  }];
let remaining = new Map();
let pairs = match(items, item => item, remaining);
console.log('pairs',...pairs);
console.log('remaining',...remaining.values());

2 个答案:

答案 0 :(得分:1)

封装&空间复杂性:

您对Set的使用是合适的,但可以通过封装匹配功能并删除全局变量来改进代码。我建议一个生成器,它产生如下匹配对,空间复杂度降低:



// Match items with first equal match:
function* match(items, equals, remaining = new Set()) {
  items: 
  for (let item of items) {
    for (let candidate of remaining) {
      if (equals(item, candidate)) {
        remaining.delete(candidate);
        yield [item, candidate];
        continue items;
      }
    }
    remaining.add(item);
  }
}

// Example:
let items = [1, 2, 5, 3, 3, 4, 2, 1, 4];
let remaining = new Set();
let pairs = match(items, (a, b) => a == b, remaining);

console.log(...pairs);
console.log(...remaining);




根据您的商品,您需要提供匹配的equals回调。在你的情况下:

let pairs = match(
  items,
  (a, b) =>
    a.type !== b.type && 
    a.direction === b.direction &&
    a.time === b.time,
  remaining
);

<强>优化

如果您可以将请求映射到原始标识值,则可以使用简单的地图查找替换for (let i of memo) { ... }循环。然后,将n个项目配对的时间复杂度降低到O(n)

但是,由于您没有匹配相同的&#39;项目但具有相反type属性的项目,此优化不能直接应用。您需要添加另一个回调,它会为我们提供匹配项的预期ID。

此外,由于您可能会遇到具有相同身份的多个请求,因此您需要multimap

&#13;
&#13;
// Multimap insertion:
function insert(map, key, value) {
  let values = map.get(key);
  if (values) values.push(value);
  else map.set(key, [value]);
}

// Multimap retrieval:
function retrieve(map, key) {
  let values = map.get(key);
  if (values) {
    let value = values.pop();
    if (values.length === 0) map.delete(key);
    return value;
  }
}

// Match items with first identical match:
function* match(items, identity, match, remaining) {
  for (let item of items) {
    let candidate = retrieve(remaining, match(item));
    if (candidate) yield [item, candidate];
    else insert(remaining, identity(item), item);
  }
}

// Example:
let items = [{
  type: 'driver',
  direction: 'east',
  time: '9:15',
  name: ['Archibald Trump']
}, {
  type: 'passenger',
  direction: 'east',
  time: '9:15',
  name: ['Bacon Eater']
}, {
  type: 'passenger',
  direction: 'east',
  time: '9:15',
  name: ['Banjo Barney']
}, {
  type: 'passenger',
  direction: 'east',
  time: '9:15',
  name: ['Flimsy Stick']
}, {
  type: 'passenger',
  direction: 'west',
  time: '9:30',
  name: ['Big Red']
}, {
  type: 'passenger',
  direction: 'west',
  time: '9:35',
  name: ['Hathaway Anne']
}];

let remaining = new Map();
let pairs = match(
  items,
  item => '' + (item.type == 'driver') + item.direction + item.time,
  item => '' + (item.type == 'passenger') + item.direction + item.time,
  remaining
);

console.log(...pairs);
console.log(...remaining.values());
&#13;
&#13;
&#13;

上述实现的运行时复杂性不容易确定,因为它取决于Array.shift()Array.push()的运行时复杂性。但是,如果我们假设这种关键冲突很少或假设JavaScript引擎在摊销的常量时间内执行这两种方法,我们仍然可以预期n项的O(n)运行时复杂性。

答案 1 :(得分:0)

地图比数组更快。您每次都可以比循环遍历数组更快地访问映射键。以下是使用地图的示例。

&#13;
&#13;
var pairs = [];
var memo = {};

function pair(item) {
    var key = item.type.toString() + item.direction + item.time;
    if(memo[key]) {
        pairs.push(item);
        delete memo[key];
    } else {
        memo[key] = item;
    }
}

var ar = [{
    type: true,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: true,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: true,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: true,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: true,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: true,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}, {
    type: false,
    direction: false,
    time: '9:00'
}];

for (let it of ar) {
  pair(it);
}

console.log('matching pairs: ', pairs);
console.log('left over nonmatching pairs:', Object.values(memo));
&#13;
&#13;
&#13;