Получение определенных столбцов CSV или n-го значения из массива PHP

#php #arrays #csv

#php #массивы #csv

Вопрос:

Я использую PHP для открытия и анализа очень маленького (около 1 КБ) CSV-файла для создания HTML-таблицы. Я новичок в PHP, и это в значительной степени экспериментально. В дополнение к созданию таблицы HTML я пытаюсь сгенерировать массив из определенного набора столбцов в этом csv (информация о городе и стране), а затем удалить повторяющиеся значения.CSV структурирован следующим образом:

 Last Name, First Name, City, Country, Language
Smith, Joe, Shanghai, China, English
Jackson, Stacey, Madrid, Spain, Spanish
Jones, Bob, London, United Kingdom, English
Seward, Elisa, Madrid, Spain, English
Harrison, Tim, Berlin, Germany, German
 

Идея здесь в том, что в дополнение к таблице со всеми данными у меня также будет список всех городов / стран, перечисленных в таблице:

  • Шанхай, Китай
  • Мадрид, Испания
  • Лондон, Великобритания
  • Берлин, Германия

Благодаря fgetcsv() документации и другим вопросам по Stack Overflow, чтение файла и построение таблицы просты:

 <?php
    $handle = fopen("namelist.csv", "r");
    $data = fgetcsv($handle, 1000, ",");
    echo('<table>');
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
        echo("<tr>rn");
        foreach ($data as $index=>$val) {
            echo("t<td>");
            echo htmlentities($val, ENT_QUOTES);
            echo("</td>rn");
        }
    echo("</tr>rn");
    }
    echo("</table>");
    fclose($handle);
?>
 

Но я не смог понять, как получить данные о городе, стране и удалить дубликаты. У кого-нибудь есть предложения?

Комментарии:

1. Я ожидаю, когда $index == 2 у вас есть город, и когда $index == 3 у вас есть страна. Чтобы удалить дубликаты, вам нужно обратиться к массиву данных или сохранить информацию в более удобном для пользователя массиве, чтобы отслеживать, что было написано.

Ответ №1:

Вот простой способ, который удаляет повторяющиеся города без необходимости их фильтрации.

 $fHandle = fopen("namelist.csv", "r");
$aData = fgetcsv($handle, 1000, ",");
while (($aData = fgetcsv($fHandle, 1000, ",")) !== FALSE) {
    $aLocations[$aData[3]] = $aData[4];
}

echo '<table>';
foreach ($aLocations as $sCity => $sCountry) {
    echo '<tr><td>'.$sCity.'</td><td>'.$sCountry.'</td></tr>';
}
echo '</table>';
 

Ответ №2:

В цикле обработки CSV сначала поля city и country соединяются запятой и проверяется массив $city_countries. Если нет дубликатов, строка city country записывается в массив $city_countries . Теги TR повторяются, а массив $data зацикливается для записи тегов TD и значений столбцов.

 $handle = fopen("namelist.csv", "r");
$data = fgetcsv($handle, 1000, ",");
$city_countries = array();
echo('<table>');
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
    $city_country = $data[2] . ', ' . $data[3];
    if ( !in_array($city_country, $city_countries) ) {
        array_push($city_countries, $city_country);
    }
    echo("<tr>rn");
    foreach ($data as $index=>$val) {
        echo("t<td>");
        echo htmlentities($val, ENT_QUOTES);
        echo("</td>rn");
    }
    echo("</tr>rn");
}
echo("</table>");
fclose($handle);

print '<pre>'; print_r($city_countries); print '</pre>';
 

Это входной файл, который я использую:

 Last Name, First Name, City, Country, Language
Smith, Joe, Shanghai, China, English
Jackson, Stacey, Madrid, Spain, Spanish
Jackson, Steve, Madrid, Spain, Spanish
Jones, Bob, London, United Kingdom, English
Seward, Elisa, Madrid, Spain, English
Harrison, Tim, Berlin, Germany, German
Jones, Bill, London, United Kingdom, English
Jackson, Ralph, Madrid, Spain, Spanish
 

И это результат, который я получаю:

 Smith    Joe     Shanghai China          English
Jackson  Stacey  Madrid   Spain          Spanish
Jackson  Steve   Madrid   Spain          Spanish
Jones    Bob     London   United Kingdom English
Seward   Elisa   Madrid   Spain          English
Harrison Tim     Berlin   Germany        German
Jones    Bill    London   United Kingdom English
Jackson  Ralph   Madrid   Spain          Spanish

Array
(
    [0] =>  Shanghai,  China
    [1] =>  Madrid,  Spain
    [2] =>  London,  United Kingdom
    [3] =>  Berlin,  Germany
)
 

Комментарии:

1. спасибо за пример — похоже, что дублирующиеся значения печатаются.

2. Ах, я вижу — код анализирует всю строку, чтобы найти дубликаты. Я хотел бы удалить дубликаты только в столбце «Город, страна», поэтому в массиве «Город, страна» должно быть только одно «Мадрид, Испания», в то время как таблица полных имен / местоположений / языков не должна фильтроваться на наличие дубликатов

3. Ah. Код изменен, чтобы перечислить все записи и сохранить уникальные комбинации городов и стран.

Ответ №3:

Попробуйте это: (На данный момент у меня нет доступа к PHP, примерно через час будут найдены крошечные ошибки)

 <?php
    $handle = fopen("namelist.csv", "r");
    $data = fgetcsv($handle, 1000, ",");
    $csv = array();
    $csv[] = array();
    $csv[] = array();
    $csv[] = array();
    $csv[] = array();
    $csv[] = array();
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
        foreach ($data as $index=>$val) {
            $column=0;
            $csv[column][] = htmlentities($val, ENT_QUOTES);
            $column  ;
        }
    }
    fclose($handle);
    //Now, csv[0] has all Last Names, csv[1] has all First Names, csv[2] all Cities, csv[3] all Countries and csv[4] all Languages
    //To filter duplicates..
    $cities = array_unique($csv[2]);
    $countries = array_unique($csv[3]);
?>
 

Это создает массив, содержащий 5 массивов (по одному для каждого столбца). Затем эти массивы заполняются каждой строкой CSV. После этого столбцы city и country очищаются от повторяющихся значений. Как указано выше, этот код ДОЛЖЕН работать, но я не смог его протестировать, если он не оставит мне комментарий, и я обязательно исправлю его позже сегодня днем.

Ответ №4:

$data[2] содержит город, и применение array_unique(...) после переноса всех значений города в массив приведет к удалению дубликатов.

 $cities = array();

while (($data = fgetcsv($handle, 1000, ",")) !== false) {
    $cities[] = $data[2];
}

$cities = array_unique($cities);

print_r($cities);
 

Обратитесь к руководству по php, в котором также есть несколько примеров кодов.

Ответ №5:

При работе с CSV, которые имеют строку заголовка, я предпочитаю сопоставлять столбцы данных с именованным ключом, поэтому мне не нужно отслеживать, к какому индексу относится конкретный столбец. Это позволяет вам ссылаться $var['ColumnName'] вместо $var[2] :

 <?php
$csvDelim = ',';
$csvEnclosure = '';

$csvArr = file('./namelist.csv', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

//create array of the csv headers
$csvHeaders = str_getcsv(trim(array_shift($csvArr)), $csvDelim, $csvEnclosure);
$csvHeaders = array_map("trim", $csvHeaders);

//get the csv data and make a multi-dim array of keys/values
$dataArr = array();
foreach($csvArr as $csvLine) 
{
    $lineData = str_getcsv(trim($csvLine), $csvDelim, $csvEnclosure);
    $lineData = array_map("trim", $lineData);
    $dataArr[] = array_combine($csvHeaders, $lineData);
}

//get unique city/country values
$locations = array();
foreach($dataArr as $da)
    $locations[] = $da['City'].', '.$da['Country'];

$locations = array_unique($locations);

//output data in table
echo '<table>';
echo '<tr>';
foreach($csvHeaders as $headerValue)
    echo '<th>'.$headerValue.'</th>';
echo '</tr>';

foreach($dataArr as $dataLine)
{
    echo '<tr>';
    foreach($dataLine as $dataValue)
    {
        echo '<td>'.htmlentities($dataValue, ENT_QUOTES).'</td>';
    }
    echo '</tr>';
}
echo '</table>';
?>
 

Комментарии:

1. спасибо за отличный пример. Я заметил, что когда я пытаюсь реализовать это, и print_r($locations) я получаю пустой массив: Array( [0] => , )

2. @Marcatectura: Извините, отсутствовали trim значения заголовка. Я обновил ответ.

Ответ №6:

я прочитал сообщение выше.

Это работает некорректно — итак, вот обновленный рабочий код Джеймса Ханта.

 <?php

$handle = fopen("test.csv", "r");
$data = fgetcsv($handle, 1000, ";");

$csv = array();
$csv[] = array();
$csv[] = array();
$csv[] = array();
$csv[] = array();
$csv[] = array();

while (($data = fgetcsv($handle, 1000, ";")) !== FALSE) {

    $column=0;

    foreach ($data as $index=>$val) {

        $csv[$column][] = htmlentities($val, ENT_QUOTES);
        $column  ;
    }

}

fclose($handle);
//Now, csv[0] has all Last Names, csv[1] has all First Names, csv[2] all Cities, csv[3] all Countries and csv[4] all Languages
//To filter duplicates..
$cities = array_unique($csv[2]);
$countries = array_unique($csv[3]);

var_dump($cities); //will output all column values of $csv[2]

?>
 

так что следите за обновлениями — приветствую Роберта!