按对象属性分组的关联数组中的对象分类

时间:2013-03-21 09:01:20

标签: php arrays json iterator

首先让我解释一下我的问题。 我有一个简单的值对象Poi。在此示例中,为了简单起见,省略了私有属性和getter / setter。

class Poi implements JsonSerializable
{
    public $latitude;
    public $longitude;
    public $category;

    public function __construct($category, $lat, $long)
    {
        $this->category = $category;
        $this->latitude = $lat;
        $this->longitude = $long;
    }

    public function jsonSerialize()
    {
        return array(
            'lat' => $this->latitude,
            'lng' => $this->longitude,
        );
    }
}

一些数据提供者负责返回一组Poi。即。

class PoiProvider1
{
    public function getPois()
    {
        return array(
            new Poi('airport', 10, 10),
            new Poi('airport', 10, 15),
            new Poi('restaurant', 30, 30),
        )
    }
}

class PoiProvider2
{
    public function getPois()
    {
        return array(
            new Poi('hotel', 20, 20),
            new Poi('airport', 30, 30),
        )
    }
}

现在我想要一个数组结构的跟随,我可以json_encode()

array(
    'airport' => array(
        new Poi('airport', 10, 10),
        new Poi('airport', 10, 15),
        new Poi('airport', 30, 30),
    ),
    'restaurant' => array(
        new Poi('restaurant', 30, 30),
    ),
    'hotel' => array(
        new Poi('hotel', 20, 20),
    )
);

在json_encode结束之后会出现以下结构:

{
    "airport":[
        {"lat":10,"lng":10},
        {"lat":10,"lng":15},
        {"lat":30,"lng":30}
    ],
    "restaurant":[
        {"lat":30,"lng":30}
    ],
    "hotel":[
        {"lat":20,"lng":20}
    ]
}

我可以使用array_merge和一些数组复制创建这样的结构,如下所示:

$provider1 = new PoiProvider1();
$provider2 = new PoiProvider2();
$pois = array_merge($provider1->getPois(), $provider2->getPois());
$poisNew = array();
foreach ($pois as $poi)
{
    $poisNew[$poi->category][] = $poi;
}

显然,当处理大量的poi时,这会消耗内存并且速度很慢。 必须有一些更好更快的方法(即使用迭代器),但我不知道如何处理这个问题。谁能给我一些指示如何继续?

1 个答案:

答案 0 :(得分:0)

为了加快速度,消除后期处理。

消除后处理:

您可以使用另一个全局或类静态容器作为pois,在构造期间自动索引和存储它们,如下所示:

class Poi implements JsonSerializable {

public static $json;    // this is our new hero.

public $latitude;
public $longitude;
public $category;

public function __construct($category, $lat, $long){
    $this->category = $category;
    $this->latitude = $lat;
    $this->longitude = $long;
    array_push(self::$json[$category], $this); // this does the trick...
}

public function jsonSerialize()
{
    return array(
        'lat' => $this->latitude,
        'lng' => $this->longitude,
    );
}
}
Poi::$json = array();

现在每次poi创建时,poi实例都以你需要的形式存储到Poi :: $ json中。

生成兴趣点

如果您不需要处理poi ,这也会简化您的提供商:

class PoiProvider1 {

public function getPois(){      // no need to return if they are just for json.
   new Poi('airport', 10, 10);  // because each instance will be autoMagically 
   new Poi('airport', 10, 15);  // added to Poi::$json
   new Poi('restaurant', 30, 30);
}
}

但如果你在poi实例上做了其他事情,请不要使用上面的代码......

<强>编码

由于$ json是一个关联数组,因此您可以使用

获得所需的输出效果
json_encode((object)Poi::$json);

缺点是poi会坚持内存并在gc中生存,因为它们可以通过Poi :: $ json访问。所以在你json_encode设置

之后
Poi::$json  = null;

我希望这会有所帮助。