Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/465.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javascript中数据分组的优化算法_Javascript_Algorithm_Grouping_Lodash - Fatal编程技术网

javascript中数据分组的优化算法

javascript中数据分组的优化算法,javascript,algorithm,grouping,lodash,Javascript,Algorithm,Grouping,Lodash,以下(简化)json类型的数据定义了联系人: { id: number; name: string; phone: string; email: string } 有以下一组数据: +---+----------+-------------+---------------------------+ |id | name | phone |email | +---+----------+------------

以下(简化)json类型的数据定义了联系人:

{
  id:   number;
  name: string;
  phone: string;
  email: string
}
有以下一组数据:

+---+----------+-------------+---------------------------+ 
|id | name     | phone       |email                      | 
+---+----------+-------------+---------------------------+
|1  | John     | 11111111    |aaaa@test.com              | 
|2  | Marc     | 22222222    |bbbb@test.com              | 
|3  | Ron      | 99999999    |aaaa@test.com              |
|4  | Andrew   | 55555555    |dddd@test.com              |
|5  | Wim      | 99999999    |gggg@test.com              |
|6  | Marc     | 33333333    |cccc@test.com              |
|7  | Dan      | 44444444    |cccc@test.com              |
+---+----------+-------------+---------------------------+
目标是根据以下约束条件,使用javascript(可以选择lodash,但主要思想是明确算法)查找属于一起的组:当以下条件相同时,联系人属于组:姓名、电话或电子邮件。结果显示id被分组为数组中的数组。一组1中的联系人将被忽略

在上面的示例中,这意味着ID为1,3,5的联系人属于一起,因为1,3共享相同的电子邮件,3和5共享相同的电话号码。同样,2,6,7:2和6有相同的名字,6和7有相同的电子邮件。5没有任何共同之处。 因此,预期结果是:
[[1,3,5],[2,6,7]]

背景: 一个有效的解决方案是迭代每个项目,如果名称、电子邮件或电话相同,则检查列表的其余部分。如果是这样,将它们分组并从列表中删除(在本例中,我们将1与列表中的所有项目进行比较,只找到3项)。问题是,还需要再次检查这些组的下一个项目,因为在这种情况下,还没有检测到5是组的一部分。这使得算法变得复杂,而我怀疑有一种简单的方法可以在线性时间内解决这个问题。这类问题也可能有一个名称?
`

实现所需功能的一种方法是将联系人分组。 每个组将包含
姓名
电话
电子邮件
的列表

然后遍历联系人,查看当前联系人是否属于任何组。如果没有,请创建一个新组并设置其
名称/电话/电子邮件
,以便下一个联系人可能会在同一时间进入同一组

var数据=[
{id:1,姓名:'John',电话:'11111111',电子邮件:'aaaa@test.com'},
{id:2,姓名:'Marc',电话:'2222',电子邮件:'bbbb@test.com'},
{id:3,姓名:'Ron',电话:'9999999',电子邮件:'aaaa@test.com'},
{id:4,姓名:'Andrew',电话:'5555',电子邮件:'dddd@test.com'},
{id:5,姓名:'Wim',电话:'9999999',电子邮件:'gggg@test.com'},
{id:6,姓名:'Marc',电话:'33333333',电子邮件:'cccc@test.com'},
{id:7,姓名:'Dan',电话:'4444',电子邮件:'cccc@test.com'}
];
var组=[];
data.forEach(功能(人员){
var phone=person.phone;
var email=person.email;
var name=person.name;
var id=person.id;
var=false;
组。forEach(函数(g){
如果(g.names.indexOf(name)>-1
||g.phones.indexOf(电话)>-1
||g.emails.indexOf(email)>-1){
发现=真;
g、 name.push(name);
g、 电话。推(电话);
g、 电子邮件。推送(电子邮件);
g、 人。推(id);
}
});
如果(!找到){
推送({names:[name]、电话:[phone]、电子邮件:[email]、人员:[id]});
}
});
var输出=[];
组。forEach(函数(g){
输出。推送(g.人);
});
控制台日志(输出)//[1,3,5],[2,6,7],[4]
创意:

  • 从0组开始
  • 迭代你的联系人列表
  • 检查是否有联系人姓名、电话或电子邮件的群组。将这些组的所有成员合并为同一组。然后把你自己加入这个小组。如果没有,请自己开始一个新的群组,并将姓名、电话和电子邮件群组设置为自己
Union find是一种处理数据合并的有效结构。代码取自。当它使用路径压缩和按等级结合时,可以考虑整个代码在联系人数量上是线性的。
var数据=[
{id:1,姓名:'John',电话:'11111111',电子邮件:'aaaa@test.com'},
{id:2,姓名:'Marc',电话:'9999999',电子邮件:'bbbb@test.com'},
{id:3,姓名:'Ron',电话:'9999999',电子邮件:'aaaa@test.com'},
{id:4,姓名:'Andrew',电话:'5555',电子邮件:'dddd@test.com'},
{id:5,姓名:'Wim',电话:'9999999',电子邮件:'gggg@test.com'},
{id:6,姓名:'Marc',电话:'33333333',电子邮件:'cccc@test.com'},
{id:7,姓名:'Dan',电话:'4444',电子邮件:'cccc@test.com'}
];
//UNION-FIND结构,具有路径压缩和按秩并集
var UNIONFIND=(函数(){
函数_find(n)
{
如果(n.parent==n)返回n;
n、 父项=_find(n.parent);
返回n.parent;
}
返回{
makeset:函数(id){
var newnode={
父项:null,
id:id,
排名:0
};
newnode.parent=newnode;
返回newnode;
},
查找:_find,
组合:函数(n1,n2){
var n1=_find(n1);
var n2=_find(n2);
如果(n1==n2)返回;
if(n1.秩const data = [
    {id:1,name:'John',phone:'11111111',email:'aaaa@test.com'},
    {id:2,name:'Marc',phone:'99999999',email:'bbbb@test.com'},
    {id:3,name:'Ron',phone:'99999999',email:'aaaa@test.com'},
    {id:4,name:'Andrew',phone:'55555555',email:'dddd@test.com'},
    {id:5,name:'Wim',phone:'99999999',email:'gggg@test.com'},
    {id:6,name:'Marc',phone:'33333333',email:'cccc@test.com'},
    {id:7,name:'Dan',phone:'44444444',email:'cccc@test.com'}
];

const groups = function(inputs) {

    let valuesToGroups = new Map(
        ['name', 'phone', 'email'].map(key => [key, new Map()]));
    let groups = new Map();
    let pendingMerges = [];
    for (const entry of inputs) {
        let group = undefined;
        let found = [];
        for (const [key, valueMap] of valuesToGroups) {
            // look up value in values-index for current key
            group = valueMap.get(entry[key]);
            if (group !== undefined) {
                found.push(group);
                // not breaking allows groups to be merged
            }
        }
        if (found.length === 0) {
            // not found: create new group
            group = groups.size;
            groups.set(group, [entry.id]);
        } else {
            // found: add entry to chosen group
            group = found[0];
            groups.get(group).push(entry.id);
            if (found.length > 1) {
                pendingMerges.push(found);
            }
        }
        // add entry's values to index, pointing to group
        for (const [key, valueMap] of valuesToGroups) {
            valueMap.set(entry[key], group); 
        }        
    }
    // do pending merges; initially, all groups are stand-alone
    let merges = new Map(Array.from(groups.keys()).map(k => [k, k]));
    for (const merge of pendingMerges) {
        // contents will go to the lowest-numbered group
        const sorted = merge.map(groupId => merges.get(groupId)).sort();
        sorted.forEach(groupId => merges.set(groupId, sorted[0]));
    }
    const cleanGroups = new Map();
    groups.forEach((value, key) => { 
        const k = merges.get(key); 
        if ( ! cleanGroups.has(k)) {
            cleanGroups.set(k, []);
        }
        value.forEach(id => cleanGroups.get(k).push(id))
    })
    // return only non-empty groups
    return [... cleanGroups].filter(g => g[1].length>1).map(g => [... g[1]]);
}(data);

console.log(""+JSON.stringify(groups))
// output is [[1,2,3,5,6,7]]