3 回答
TA贡献1844条经验 获得超8个赞
虽然没有内置的东西可以直接开箱即用,但也不需要大量代码来处理任意数量的属性以考虑唯一性。通过跟踪查找数组中的每个唯一属性,我们可以构建一个数组,其中叶节点(即那些本身不是数组的节点)是对象。
为此,我们&在数组中保留对当前级别的引用 ( ),然后继续为每个属性构建我们的查找数组。
function find_uniques($list, $properties) {
$lookup = [];
$unique = [];
$last_idx = count($properties) - 1;
// Build our lookup array - the leaf nodes will be the items themselves,
// located on a level that matches the number of properties to look at
// to consider a duplicate
foreach ($list as $item) {
$current = &$lookup;
foreach ($properties as $idx => $property) {
// last level, keep object for future reference
if ($idx == $last_idx) {
$current[$item->$property] = $item;
break;
} else if (!isset($current[$item->$property])) {
// otherwise, if not already set, create empty array
$current[$item->$property] = [];
}
// next iteration starts on this level as its current level
$current = &$current[$item->$property];
}
}
// awr only calls the callback for leaf nodes - i.e. our items.
array_walk_recursive($lookup, function ($item) use (&$unique) {
$unique[] = $item;
});
return $unique;
}
使用上面的数据调用,并且要求是唯一的并且返回重复项的最后一个元素,我们得到以下结果:
var_dump(find_uniques($animArray, ['dp', 'cg']));
array(2) {
[0] =>
class anim#1 (4) {
public $qs =>
string(4) "fred"
public $dp =>
string(6) "shorts"
public $cg =>
string(4) "dino"
public $timestamp =>
int(1590157029399)
}
[1] =>
class anim#3 (4) {
public $qs =>
string(4) "fred"
public $dp =>
string(6) "tshirt"
public $cg =>
string(4) "bird"
public $timestamp =>
int(1590117032286)
}
}
在您的示例中映射到 element[0]和 element [2]。如果您想要保留第一个对象以备重复,请添加一个 isset 以在属性值已被看到时终止内部循环:
foreach ($properties as $idx => $property) {
if ($idx == $last_idx) {
if (isset($current[$item->$property])) {
break;
}
$current[$item->$property] = $item;
} else {
$current[$item->$property] = [];
}
// next iteration starts on this level as its current level
$current = &$current[$item->$property];
}
重要的是要注意,这是在假设您要检查唯一性的数组本身不包含数组的情况下编写的(因为我们正在查找属性,并且因为我们正在使用查找->任何array_walk_recursive不是大批)。
TA贡献1805条经验 获得超10个赞
这很有趣:
array_multisort(array_column($animArray, 'timestamp'), SORT_DESC, $animArray);
$result = array_intersect_key($animArray,
array_unique(array_map(function($v) { return $v->dp.'-'.$v->cg; }, $animArray)));
首先,提取timestamp并对该数组进行降序排序,从而对原始数组进行排序。
dp然后,映射以使用和组合创建一个新数组cg。
接下来,使组合数组唯一,这将保留遇到的第一个重复项(这就是我们降序排序的原因)。
最后,得到原始数组的键和唯一键的交集。
在具有动态属性的函数中:
function array_unique_custom($array, $props) {
array_multisort(array_column($array, 'timestamp'), SORT_DESC, $array);
$result = array_intersect_key($array,
array_unique(array_map(function($v) use ($props) {
return implode('-', array_map(function($p) use($v) { return $v->$p; }, $props));;
},
$array)));
return $result;
}
$result = array_unique_custom($animArray, ['dp', 'cg']);
另一种选择是将其升序排序,然后构建一个以 adp和cg组合为键的数组,这将保留最后一个副本:
array_multisort(array_column($animArray, 'timestamp'), SORT_ASC, $animArray);
foreach($animArray as $v) {
$result[$v->dp.'-'.$v->cg] = $v;
}
在具有动态属性的函数中:
function array_unique_custom($array, $props) {
array_multisort(array_column($array, 'timestamp'), SORT_ASC, $array);
foreach($array as $v) {
$key = implode(array_map(function($p) use($v) { return $v->$p; }, $props));
$result[$key] = $v;
}
return $result;
}
$result = array_unique_custom($animArray, ['dp', 'cg']);
TA贡献1829条经验 获得超4个赞
//Create an array with dp and cg values only
$new_arr = [];
foreach($animArray as $key=>$item) {
$new_arr[] = $item->dp.','.$item->cg;
}
$cvs = array_count_values($new_arr);
$final_array = [];
foreach($cvs as $cvs_key=>$occurences) {
if ($occurences == 1) {
$filter_key = array_keys($new_arr, $cvs_key)[0];
$final_array[$filter_key] = $animArray[$filter_key];
}
}
最终结果将是(根据您的示例)$final_array:
[0] => anim Object
(
[qs] => fred
[dp] => shorts
[cg] => dino
[timestamp] => 1590157029399
)
一些解释:
//Create a new array based on your array of objects with the attributes dp and cg
//with a comma between them
$new_arr = [];
foreach($animArray as $key=>$item) {
$new_arr[] = $item->dp.','.$item->cg;
}
/*
$new_arr now contains:
[0] => shorts,dino
[1] => tshirt,bird
[2] => tshirt,bird
*/
//Use builtin-function array_count_values to get the nr of occurences for
//each item in an array
$cvs = array_count_values($new_arr);
/*
$cvs would contain:
(
[shorts,dino] => 1
[tshirt,bird] => 2
)
*/
//Iterate through the $cvs array.
//Where there are only one occurence (no duplicates)
//create a final array $final_array
$final_array = [];
foreach($cvs as $cvs_key=>$occurences) {
if ($occurences == 1) {
/*
array_keys with second argument $csv_key searches for key with
with the key from $cvs-key
so basically search for:
shorts,dino and retrieve the key 0 (first element)
*/
$filter_key = array_keys($new_arr, $cvs_key)[0];
/*
Add a new item to the $final_array based on the key in
the original array $animArray
if you don't want the original key in the new array
you could just do $final_array[] instead of
$final_array[$filter_key]
*/
$final_array[$filter_key] = $animArray[$filter_key];
}
}
你说你想要某种功能测试不同的属性。我相信它只是制作一个函数/方法,您将两个值传递给参数$attr1 ('dp'?), $attr2('cg'?)或类似的东西。
更新
我没有意识到你也想要最后一个值。这实际上似乎是一项更容易的任务。也许我遗漏了一些东西,但是想出一种与其他答案不同的方法很有趣 :-)
//Create an array with dp and cg values only
$new_arr = [];
foreach($animArray as $key=>$item) {
$new_arr[] = $item->dp.','.$item->cg;
}
//Sort keys descending order
krsort($new_arr);
//Because of sending order of keys above, the unique values would return the
//last item of the duplicates
$new_arr2 = array_unique($new_arr);
//Switch order of keys back to normal (ascending)
ksort($new_arr2);
//Create a new array based on the keys set in $new_arr2
//
$final_arr = [];
foreach($new_arr2 as $key=>$item) {
$final_arr[] = $animArray[$key];
}
的输出$final_arr[]将是(在你的例子中)
Array
(
[0] => anim Object
(
[qs] => fred
[dp] => shorts
[cg] => dino
[timestamp] => 1590157029399
)
[1] => anim Object
(
[qs] => fred
[dp] => tshirt
[cg] => bird
[timestamp] => 1590117032286
)
)
- 3 回答
- 0 关注
- 228 浏览
添加回答
举报