如何在 PodioItemCollection 响应中找到多个重复项?
How to find multiple duplicates in a PodioItemCollection response?
我有一个数组,其中有一些已注册课程的学生。有多个重复项,每个课程应该只有一个学生。
示例数组:
'item_id'=> 1, 'student'=> 'Bob', 'course'=> 'Learn Piano', 'address'=>''
'item_id'=> 2, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=> 'foo street'
'item_id'=> 3, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=>''
'item_id'=> 4, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=>''
'item_id'=> 5, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=> 'bla bla street'
'item_id'=> 6, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=>''
'item_id'=> 7, 'student'=> 'John', 'course'=> 'Learn Guitar', 'address'=>''
通过 API 访问数据(否则整个事情将是一个简单的 SQL 查询!)。
原始数据如下所示:
object(PodioItemCollection)#287 (5) { ["filtered"]=> int(45639) ["total"]=> int(45639) ["items"]=> NULL ["__items":"PodioCollection":private]=> array(10) { [0]=> object(PodioItem)#3 (5) { ["__attributes":"PodioObject":private]=> array(16) { ["item_id"]=> int(319357433) ["external_id"]=> NULL ["title"]=> string(12) "Foo Bar" ["link"]=> string(71) "https://podio.com/foo/enrolments/apps/applications/items/123" ["rights"]=> array(11) ...
挑战是我不能只使用 array_unique 或类似的,因为我需要:
- 查找学生 + 课程的所有重复项
- 相互比较找到的重复项并保留具有最多补充信息的项目(或合并它们)
- 获取重复项不需要的 "item_id" 并使用 API 删除项目。
进一步限制:
- 我无法控制 API。
- 有 44,000 条记录
- 每人 + 课程最多可重复 100 次
- API returns 的嵌套层次结构
对象,所以 44,000 条记录使用 27GB RAM(服务器有 144GB
玩) 是的 php_memory 限制设置为荒谬
等级!!!这是一个单一的项目,将采取措施
之后更正服务器变量。
- 由于 RAM 使用量大,array_intersect 之类的东西将成为不太受欢迎的选择
最终输出应该是:
'item_id'=> 1, 'student'=> 'Bob', 'course'=> 'Learn Piano', 'address'=>''
'item_id'=> 2, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=> 'foo street'
'item_id'=> 5, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=> 'bla bla street'
'item_id'=> 7, 'student'=> 'John', 'course'=> 'Learn Guitar', 'address'=>''
但我还需要访问“item_id”的 3、4、6 以便我可以通过 API.
调用删除例程
有什么想法可以解决这个多重复的问题吗?
以下函数将为您完成这项工作:
$apiData = array(
array('item_id'=> 1, 'student'=> 'Bob', 'course'=> 'Learn Piano', 'address'=>''),
array('item_id'=> 2, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=> 'foo street'),
array('item_id'=> 3, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=>''),
array('item_id'=> 4, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=>''),
array('item_id'=> 5, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=> 'bla bla street'),
array('item_id'=> 6, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=>''),
array('item_id'=> 7, 'student'=> 'John', 'course'=> 'Learn Guitar', 'address'=>'')
);
function resolveDuplicate($apiData = null)
{
if(!$apiData) return false;
foreach ($apiData as $key => $arr) {
$key = $arr['student'] . ':' . $arr['course'];
if(!$newArr[$key]['address']){
if($newArr[$key]) $itemIds[] = $newArr[$key]['item_id'];
$newArr[$key] = $arr;
}
else{
$itemIds[] = $arr['item_id'];
}
}
if($newArr){
foreach ($newArr as $value) {
$finalArr[] = $value;
}
}
$result['student'] = $finalArr;
$result['duplicates'] = $itemIds;
return $result;
}
$res = resolveDuplicate($apiData);
echo '<pre>';
print_r($res);
输出
Array
(
[student] => Array
(
[0] => Array
(
[item_id] => 1
[student] => Bob
[course] => Learn Piano
[address] =>
)
[1] => Array
(
[item_id] => 2
[student] => Sam
[course] => Learn Piano
[address] => foo street
)
[2] => Array
(
[item_id] => 5
[student] => Bob
[course] => Learn Guitar
[address] => bla bla street
)
[3] => Array
(
[item_id] => 7
[student] => John
[course] => Learn Guitar
[address] =>
)
)
[duplicates] => Array
(
[0] => 4
[1] => 3
[2] => 6
)
)
您似乎在尝试修复 XY problem by parsing all the items at the same time, when actually you just need to read about Podio API 以及如何使用 PodioObjects API.
所以不是遍历整个数组,而是遍历对象(在本例中为PodioItemCollection
),通过键字段(例如student
)对其进行排序,例如:
PodioItem::filter(31060, array('limit' => 20, 'offset' => 20, 'sort_by' => 'student'));
然后(假设排序标准)您知道如果有一些重复项(学生 + 课程),它们是连续的。因此,只要你在下一行中有相同的学生姓名,就将其视为重复并忽略其他行(除非你想将它们作为当前学生对象的一部分进行处理),然后转到下一项。
在这种情况下,您可以避免同时处理所有记录,因此不会有任何内存问题。
如果内存问题仍然是个问题,使用NOSQL解决方案,如memcached或redis,将解析的项目存储在内存中,释放PHP中的变量,转到下一个,最后检查一致性(例如计算项目)。还请考虑禁用您拥有的任何额外 PHP 扩展,这些扩展可能会减慢处理速度(例如 xdebug 和类似的)。
另请参阅:
- Working with items - Podio API
- Aggregating responses for a PodioItem:filter() call 在 SO
我有一个数组,其中有一些已注册课程的学生。有多个重复项,每个课程应该只有一个学生。
示例数组:
'item_id'=> 1, 'student'=> 'Bob', 'course'=> 'Learn Piano', 'address'=>''
'item_id'=> 2, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=> 'foo street'
'item_id'=> 3, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=>''
'item_id'=> 4, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=>''
'item_id'=> 5, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=> 'bla bla street'
'item_id'=> 6, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=>''
'item_id'=> 7, 'student'=> 'John', 'course'=> 'Learn Guitar', 'address'=>''
通过 API 访问数据(否则整个事情将是一个简单的 SQL 查询!)。
原始数据如下所示:
object(PodioItemCollection)#287 (5) { ["filtered"]=> int(45639) ["total"]=> int(45639) ["items"]=> NULL ["__items":"PodioCollection":private]=> array(10) { [0]=> object(PodioItem)#3 (5) { ["__attributes":"PodioObject":private]=> array(16) { ["item_id"]=> int(319357433) ["external_id"]=> NULL ["title"]=> string(12) "Foo Bar" ["link"]=> string(71) "https://podio.com/foo/enrolments/apps/applications/items/123" ["rights"]=> array(11) ...
挑战是我不能只使用 array_unique 或类似的,因为我需要:
- 查找学生 + 课程的所有重复项
- 相互比较找到的重复项并保留具有最多补充信息的项目(或合并它们)
- 获取重复项不需要的 "item_id" 并使用 API 删除项目。
进一步限制:
- 我无法控制 API。
- 有 44,000 条记录
- 每人 + 课程最多可重复 100 次
- API returns 的嵌套层次结构 对象,所以 44,000 条记录使用 27GB RAM(服务器有 144GB 玩) 是的 php_memory 限制设置为荒谬 等级!!!这是一个单一的项目,将采取措施 之后更正服务器变量。
- 由于 RAM 使用量大,array_intersect 之类的东西将成为不太受欢迎的选择
最终输出应该是:
'item_id'=> 1, 'student'=> 'Bob', 'course'=> 'Learn Piano', 'address'=>''
'item_id'=> 2, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=> 'foo street'
'item_id'=> 5, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=> 'bla bla street'
'item_id'=> 7, 'student'=> 'John', 'course'=> 'Learn Guitar', 'address'=>''
但我还需要访问“item_id”的 3、4、6 以便我可以通过 API.
调用删除例程有什么想法可以解决这个多重复的问题吗?
以下函数将为您完成这项工作:
$apiData = array(
array('item_id'=> 1, 'student'=> 'Bob', 'course'=> 'Learn Piano', 'address'=>''),
array('item_id'=> 2, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=> 'foo street'),
array('item_id'=> 3, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=>''),
array('item_id'=> 4, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=>''),
array('item_id'=> 5, 'student'=> 'Bob', 'course'=> 'Learn Guitar', 'address'=> 'bla bla street'),
array('item_id'=> 6, 'student'=> 'Sam', 'course'=> 'Learn Piano', 'address'=>''),
array('item_id'=> 7, 'student'=> 'John', 'course'=> 'Learn Guitar', 'address'=>'')
);
function resolveDuplicate($apiData = null)
{
if(!$apiData) return false;
foreach ($apiData as $key => $arr) {
$key = $arr['student'] . ':' . $arr['course'];
if(!$newArr[$key]['address']){
if($newArr[$key]) $itemIds[] = $newArr[$key]['item_id'];
$newArr[$key] = $arr;
}
else{
$itemIds[] = $arr['item_id'];
}
}
if($newArr){
foreach ($newArr as $value) {
$finalArr[] = $value;
}
}
$result['student'] = $finalArr;
$result['duplicates'] = $itemIds;
return $result;
}
$res = resolveDuplicate($apiData);
echo '<pre>';
print_r($res);
输出
Array
(
[student] => Array
(
[0] => Array
(
[item_id] => 1
[student] => Bob
[course] => Learn Piano
[address] =>
)
[1] => Array
(
[item_id] => 2
[student] => Sam
[course] => Learn Piano
[address] => foo street
)
[2] => Array
(
[item_id] => 5
[student] => Bob
[course] => Learn Guitar
[address] => bla bla street
)
[3] => Array
(
[item_id] => 7
[student] => John
[course] => Learn Guitar
[address] =>
)
)
[duplicates] => Array
(
[0] => 4
[1] => 3
[2] => 6
)
)
您似乎在尝试修复 XY problem by parsing all the items at the same time, when actually you just need to read about Podio API 以及如何使用 PodioObjects API.
所以不是遍历整个数组,而是遍历对象(在本例中为PodioItemCollection
),通过键字段(例如student
)对其进行排序,例如:
PodioItem::filter(31060, array('limit' => 20, 'offset' => 20, 'sort_by' => 'student'));
然后(假设排序标准)您知道如果有一些重复项(学生 + 课程),它们是连续的。因此,只要你在下一行中有相同的学生姓名,就将其视为重复并忽略其他行(除非你想将它们作为当前学生对象的一部分进行处理),然后转到下一项。
在这种情况下,您可以避免同时处理所有记录,因此不会有任何内存问题。
如果内存问题仍然是个问题,使用NOSQL解决方案,如memcached或redis,将解析的项目存储在内存中,释放PHP中的变量,转到下一个,最后检查一致性(例如计算项目)。还请考虑禁用您拥有的任何额外 PHP 扩展,这些扩展可能会减慢处理速度(例如 xdebug 和类似的)。
另请参阅:
- Working with items - Podio API
- Aggregating responses for a PodioItem:filter() call 在 SO