【问题标题】:Removing duplicates from merged array从合并数组中删除重复项
【发布时间】:2019-03-07 03:52:40
【问题描述】:

我一直在这里做一些名称处理器,但我遇到了一些小问题。

我有包含名称和状态的 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
    )

不知道接下来会发生什么 - 如果我查询的名称与第一个 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 文件,在那里它可以被输出。

非常感谢!

【问题讨论】:

  • 你能把你的both数组以json格式给我们吗?
  • 警告:使用 PDO 时,您应该使用带有占位符值的 prepared statements,并将任何用户数据作为单独的参数提供。在此代码中,您可能有严重的SQL injection bugs。永远不要使用字符串插值或连接,而是使用 prepared statements 并且永远不要将 $_POST$_GET 或任何用户数据直接放在查询中。有关一般指导和建议,请参阅 PHP The Right Way
  • 非常感谢朋友们的关心!我首先对 $eid 进行了消毒。我是一个周日的编码员,但我需要做更好的技术。
  • $newArray = array_unique( array_merge($arr_1, $arr_2)); 试试这个..
  • 一些提示将$sth->fetchAll(PDO::FETCH_NUM) 更改为$sth->fetchAll(PDO::FETCH_GROUP) 并添加GROUP BY guestName 无论如何你都会丢失表格中的任何重复项,然后对于csv,你可以使用array_column($data,null,0) Example这些应该让你接近你所需要的,结构明智。

标签: php mysql arrays


【解决方案1】:

一些事情,

我们需要做的是合并两个数组,但控制哪一个覆盖另一个。我不确定您现在是否(以可靠的方式)这样做,但一种方法是构建 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就很简单了。

要提一提的是,如果您的 DB 或 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 用作返回数组的索引/键的列。该值可能是列的整数键,也可能是字符串键名。像往常一样为数组键转换值(但是,也允许支持转换为字符串的对象)。

【讨论】:

  • 谢谢!到处调整,但你的解释是完全完美的。 TIL:array_columns - 太棒了!
【解决方案2】:

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

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

遍历用户数组。

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

密钥应该是用户名。

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

代码:

$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
)

【讨论】:

    【解决方案3】:

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

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

    有时我真的很喜欢为你寻求帮助,因为它让我思考!比平时更深入地思考。

    【讨论】:

    • i want that if my queried name is same as in this first CSV file, then hide this one, and show mine. - 虽然我不完全确定这意味着什么,但您可能遇到的一个问题是您无法控制保留哪个副本。现在它可能基于它们在合并数组中的顺序。
    • 控制这种情况的方法是构建两个数组,每个数组都具有相同的结构,名称作为数组的键。一个用于文件,一个用于数据库。然后,当您使用 array_merge 时,它将使用键,但您可以根据每个数组的参数来控制替换哪个键。第二个参数替换第一个参数中的项目。 For Example
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2017-06-22
    • 2021-06-19
    • 2014-01-24
    • 2011-01-09
    • 2011-06-29
    相关资源
    最近更新 更多