从合并数组中删除重复项

时间:2019-03-07 03:52:40

标签: php mysql arrays

我在这里做过一些名字处理程序,但是遇到了一些小问题。

我有一个带有名称和状态的CSV文件,仅按“ Cool Ones”状态过滤它们,然后我要查询SQL,并获得另一个我手动输入的名称列表。 因此,这是代码示例,其中我要获取CSV文件,过滤器,查询SQL,然后创建数组,将其合并并按字母顺序排序。

   $nameFile = "names/$eid.csv";
            $content = array_map('str_getcsv', file($nameFile));
            $filteredData = array_filter($content, function($v){
            return $v['1'] === 'Cool Ones'; },ARRAY_FILTER_USE_BOTH); //because in this file there are also 'Not Cool Ones'

            $freePeople = array(); 
            $sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = '$eid' ORDER BY 'guestName'");
            $sth->execute();
            $result2 = $sth->fetchAll(PDO::FETCH_NUM);

            $listNames = array();
            foreach($result2 as $row) {
               $listNames[] = $row['0'];
               $freeGuestName = $row['0'];
               $freeGuestType = $row['1'];
            }

            $merged = array_merge($filteredData, $result2);
            $sortedGuests = usort($merged, "sortGuestNames");

所以我的问题在于,当输出数组时,我得到重复的结果,

[50] => Array
    (
        [0] => John Down
        [1] => Best Ones
    )

[51] => Array
    (
        [0] => John Down
        [1] => Cool Ones
    )

Dunno下一步是什么-我想要的是,如果我查询的名称与第一个CSV文件中的名称相同,然后隐藏该名称并显示我的名称。

我试图用取消设置密钥

foreach($merged[$i]['0'] as $key => $value) {
if (in_array($merged[$i]['0'], $value)) {
    unset($merged[$i]['0'][$key]);
}

}

但没有运气,仍然输出重复项。

您可以建议更好的方法。 我想过-也许打开CSV,查询SQL并找到我的手册名称-在打开的CSV字段中查找,在其中附加我的状态,合并并将其推送到SQL数据库或新的CSV文件中,即可将其输出。

非常感谢!

3 个答案:

答案 0 :(得分:0)

假设您需要唯一的用户名,下面是解决方法。

创建一个新的空白用户数组。

遍历users数组。

将用户追加到新用户数组。

密钥应为用户名。

因此,同一位用户每次来访时,他都会覆盖前一个用户,并删除重复的用户。

代码:

$users = [
 ['John Down', 'Best Ones'],
 ['John Down', 'Cool Ones']
];
$newUsers = [];
if (! empty($users)) {
 foreach ($users as $user) {
   $newUsers[$user[0]] = $user[1];
 }
}
echo '<pre>';print_r($newUsers);echo '</pre>';

// Output:
Array
(
    [John Down] => Cool Ones
)

答案 1 :(得分:0)

我解决了案件: 我从合并数组中删除了第二个键,然后对其进行反序列化,并且仅映射了唯一的键!现在一切正常!

$input = array_map("unserialize", array_unique(array_map("serialize", $merged)));

有时候,我真的很喜欢为您寻求帮助,因为这让我思考!要比平常更深入地思考。

答案 2 :(得分:0)

几件事,

我们需要做的是合并两个数组,但是控制哪个覆盖另一个。我不确定您现在是否(以一种可靠的方式)做到了,但是做到这一点的一种方法是构建2个数组。两者都具有相同的结构,并且密钥是您唯一的字段,因此我们需要这样做:

$csv = ['John Down' =>  ['John Down','Best Ones']];   
$db = ['John Down' => ['John Down','Cool Ones']];

然后,当我们进行数组合并时,第二个参数将覆盖第一个参数。所以如果我们这样做

$csv = ['John Down' =>  ['John Down','Best Ones']];
$db = ['John Down' => ['John Down','Cool Ones']];

print_r(array_merge($csv, $db));
echo "\n";
print_r(array_merge($db, $csv));

输出:

// print_r(array_merge($csv, $db));
Array
(
    [John Down] => Array
        (
            [0] => John Down
            [1] => Cool Ones
        )

)

//print_r(array_merge($db, $csv))
Array
(
    [John Down] => Array
        (
            [0] => John Down
            [1] => Best Ones
        )

)

Sandbox

如您所见,我们可以控制将数组发送到array_merge的顺序来覆盖哪个数组。第二个数组(或右边的数组)将覆盖左边的数组。因此,它从左到右读取。

那么,现在从数据库中获取该结构的最简单方法是什么?在PDO中,我们可以使用FETCH_GROUP来获取查询的第一列并将其用作顶级键。

$sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = :eid GROUP BY guestName ORDER BY guestName");
//-- add `GROUP BY guestName` we don't want duplicates anyway
//-- no quotes see: ... ORDER BY 'guestName');
//-- use prepared statements
$sth->execute(['eid'=>$eid]);            
$result2 = $sth->fetchAll(PDO::FETCH_NUM);

$result2 = array_column($result2, null, 0);

对于CSV,您可以在读取文件(通过添加密钥)并使用fgetcsv时以这种方式构建它,也可以使用此技巧(也在上面使用):

$csv = [['John Down','Best Ones']];

print_r(array_column($csv, null, 0));

输出

Array
(
    [John Down] => Array
        (
            [0] => John Down
            [1] => Best Ones
        )

)

Sandbox

基本上应该给您提供我们所需要的东西,那么使用array_merge就很简单。

要提到的一件事是,如果您的数据库或CSV不是唯一的,那么您在该数据库中也会得到一些重复删除,您可能必须考虑到这一点。

删除重复项很好,但是您要确保以可重复且可靠的方式删除正确的重复项。使用array_merge,我们可以控制行从数据库和文件进入的顺序。

摘要

因此,如果我们将所有这些放在一起,这就是您所需要的:

$nameFile = "names/$eid.csv";
$content = array_map('str_getcsv', file($nameFile));
$filteredData = array_filter($content, function($v){
    return $v['1'] === 'Cool Ones';
},ARRAY_FILTER_USE_BOTH); //because in this file there are also 'Not Cool Ones'

$sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = :eid GROUP BY guestName ORDER BY guestName");
$sth->execute(['eid'=>$eid]);            
$result2 = $sth->fetchAll(PDO::FETCH_NUM);

$listNames = array_column($result2, 0);

$merged = array_merge(array_column($filteredData, null, 0), array_column($result2, null, 0));
$sortedGuests = usort($merged, "sortGuestNames");

因此,我们没有在为问题打补丁时添加代码,而是找到了根本原因并将其修复,并将代码减少了几行。只要您的CSV格式正确,此功能就可以使用。 guestName, guestType

干杯!

http://php.net/manual/en/function.array-column.php

  

array_column(数组 $ input ,混合 $ column_key [,混合 $ index_key = NULL]):数组

     

array_column()返回输入的单个列中的值,该值由column_key标识。可选地,可以提供index_key以通过输入数组的index_key列中的值索引返回的数组中的值。

     

输入:要从中提取一列值的多维数组或对象数组。如果提供了对象数组,则可以直接提取公共属性。为了提取受保护的属性或私有属性,该类必须同时实现__get()和__isset()魔术方法。

     

column_key 要返回的值列。此值可以是您要检索的列的整数键,也可以是关联数组或属性名称的字符串键名。返回完整的数组或对象也可能为NULL(这与index_key一起用于重新索引数组很有用)。

     

index_key 用作返回数组的索引/键的列。此值可以是列的整数键,也可以是字符串键名。该值将照常转换为数组键(但是,也允许支持转换为字符串的对象)。