【问题标题】:How to compare an array of objects, and merge the value of a shared property when there's a match?如何比较对象数组,并在匹配时合并共享属性的值?
【发布时间】:2017-09-08 17:26:56
【问题描述】:

背景

在我正在进行的一个项目中,我创建了一个 Builder 类,其中包含一些以不同方式构建其对象的方法。我们就叫它CompanyBuilder吧。

CompanyBuilder 负责构建三个对象:CompanyEmployeeSkill。在每个组装方法中,它会在每个对象中注入一些依赖项。

对象

这些是它负责构建的对象,我知道这里有四个,但是有三个主要对象。

class Company {
    public $name;
    public $employees = array();

    public function __construct($name) {
        $this->name = $name;
    }
}

class Person {
    public $name;
}

class Employee extends Person {
    public $job;
    public $skills = array();
}

class Skill {
    public $name;

    public function __construct($name) {
        $this->name = $name;
    }
}

建造者

构建器中有三种方法旨在在构建对象时提供灵活性。产生此问题的问题如下所示:

$company = $companyBuilder->buildCompany(
    'Acme',
    $dependency,
    $employee,
    array(
        $skillOne,
        $skillTwo,
        $skillThree
    )
);

这样做的结果将是 一个 公司对象,其中 一个 员工具有 一种或多种 技能。这种方法符合业务目标。但是,有一个问题。

问题

当我有不同的 Company 对象时出现问题,这些对象包含相同的 name 属性。如果Company 名称匹配,我想将员工合并到一个Company 对象中。

我曾想过我可以创建一个mergeEmployees 方法,它可以接收不确定数量的Company 对象作为参数,这些对象是使用func_get_args() 捕获的,这会将它们变成一个对象数组。我试过this solution,但对我没有用。

想要在该数组中找到一家具有相同名称的公司并合并它的员工。所以如果 args 数组看起来像这样:

Company Object
(
    [name] => Acme
    [employees] => Array
        (
            [0] => Employee Object
                (
                    [job] => Designer
                    [skills] => Array
                        (
                            [0] => Skill Object
                                (
                                    [name] => web
                                )

                            [1] => Skill Object
                                (
                                    [name] => ui
                                )

                        )

                    [name] => Jacob
                )

        )

)
Company Object
(
    [name] => Scholastic
    [employees] => Array
        (
            [0] => Employee Object
                (
                    [job] => Developer
                    [skills] => Array
                        (
                            [0] => Skill Object
                                (
                                    [name] => java
                                )

                            [1] => Skill Object
                                (
                                    [name] => c#
                                )

                        )

                    [name] => Steve
                )

        )

)
Company Object
(
    [name] => Acme
    [employees] => Array
        (
            [0] => Employee Object
                (
                    [job] => Designer
                    [skills] => Array
                        (
                            [0] => Skill Object
                                (
                                    [name] => ux
                                )

                            [1] => Skill Object
                                (
                                    [name] => css
                                )

                        )

                    [name] => Jacob
                )

        )

)

我将如何对这个对象数组进行比较,发现Employee Jacob 应该具有他的“UX”和“CSS”技能,并将其(可靠地)与他以前的 Employee 对象的技能合并?

我曾尝试使用 array_reduce(),但它对我不起作用 --- 肯定是在滥用它,因为它的目的是:

使用回调函数迭代地将数组缩减为单个值

我想使用array_filter(),但它只向我传递了回调函数中的一项,这不足以进行比较。除非我错过了什么。

做这样的事情最好的方法是什么?

【问题讨论】:

  • 两个相同但属性不同的对象肯定是不一样的定义
  • 我在发布后不久就意识到了这一点,并进行了编辑以使意图更清晰。
  • 同一员工在两个不同的公司怎么办?
  • 您应该阻止创建新对象,只更新第一个对象。对象引用将为您完成剩下的工作。
  • @Luka 在这种情况下,员工的技能不需要合并,因为它们在不同的公司中使用。

标签: php class oop


【解决方案1】:

我建议已经在 buildCompany 方法中实现:

function buildCompany($companyName, $employeeName, $skills){
    //let's say existing companies are in $companies array
    $existingCompany = false;

    foreach($companies as $key => $company){
        if($company->name === $companyName){
            $existingCompany = true;

            $existingEmployee = false;
            foreach($company->employees as $keyE => $employee){
                if($employee->name === $employeeName){
                    $existingEmployee = true;
                    $employee->skills = array_unique(array_merge($employee->skills, $skills), SORT_REGULAR); //http://stackoverflow.com/questions/13469803/php-merging-two-array-into-one-array-also-remove-duplicates
                    break;
                }
            }

            if(!$existingEmployee){
                $company->employees[] = new Employee($employeeName, $skills); // add a constructor to the Employee, i see it's missing (or just not provided)
            }
        }
    }
    if(!$existingCompany){
        $temp = new Company($companyName);
        $temp->employees[] = new Employee($employeeName, $skills); // add a constructor to the Employee, i see it's missing (or just not provided)
        $companies[] = $temp;
    }
}

【讨论】:

  • [count($companies) - 1]->employees 位在做什么?是否只是将员工添加到最后添加的公司?似乎最好:$company = new Company($companyName); $company->employees[] = new Employee($employeeName, $skills); $companies[] = $company; 或其他东西,否则这看起来像我正在寻找的东西。我在第一个 foreach 之前在公司数组上添加了一个空检查。
  • 好的,我同意你的两个改进,很高兴看到你理解代码:)
  • 但是,没有必要检查空数组,因为 foreach 已经为您完成了这项工作
  • 正确,如果初始化正确的话。 ;)
猜你喜欢
  • 1970-01-01
  • 2021-02-04
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
  • 2021-01-11
相关资源
最近更新 更多