简体   繁体   English

如何按PHP中的特定列对列的多维数组进行排序?

[英]How to sort a multidimensional array of columns by a specific column in PHP?

I found on the PHP documentation the function "array_multisort" that is meant to sort an array "of columns". 我在PHP文档中发现了用于对数组“列”进行排序的函数“ array_multisort”。 They provide one example where the user has an array of rows and then the user has to transform this array of rows into an array of columns. 他们提供了一个示例,其中用户具有一个行数组,然后用户必须将该行数组转换为列数组。 In my case the array is already set by columns, such as: 在我的情况下,数组已经由列设置,例如:

tablearray 

{

['Employee_ID'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}

['First_Name'] = {0 => row1, 1 => row2, 2 => row3, 3 => row4}

['LastName'] = {0 => row1, 1 => row2, 2 => row3, 3 =>row4}

 }

I want to sort by Employee_ID and I need all the other columns to follow the same order. 我想按Employee_ID排序,我需要所有其他列遵循相同的顺序。 I tried: 我试过了:

   array_multisort($tablearray['Employee_ID'], SORT_ASC);

But it only sorts the first column (which becomes a mess). 但是,它仅对第一列进行排序(变成一团糟)。 The array has more than 10 columns and it changes the column names depending on the search (the columns names are its keys). 该数组有10多个列,它根据搜索更改列名称(列名称是其键)。 On PHP's documentation for this function, the example provided shows that the after transforming the rows array into a columns array, we should use the original array as a third parameter to match the keys - I don't have the "original" array to do the match since I didn't transform anything. 在PHP的此函数的文档中,提供的示例显示,在将rows数组转换为columns数组之后,我们应该使用原始数组作为与键匹配的第三个参数-我没有“ original”数组要做比赛,因为我没有改变任何东西。

Thank you. 谢谢。


Desired output, as suggested by one user: 一位用户建议的所需输出:

Original:

array
{

['Employee_ID'] = (1002, 4508, 0002, 1112)
['Business_Unit'] = ('UER', 'ABC', 'XYZ', 'EER')
['LastName'] = ('Smith', 'Vicente', 'Simpson', 'Thompson')

}

Sorted by Employee ID:

array
{

['Employee_ID'] = (0002, 1002, 1112, 4508)
['Business_Unit'] = ('XYZ', 'UER', 'EER', 'ABC')
['LastName'] = ('Simpson','Smith', 'Thompson', 'Vicente')

}

-- My original array is a database query output: -我的原始数组是数据库查询输出:

Array
 (
[0] => Array
    (
        [Employee_ID] => 0000
        [Supervisor_ID] => 00000
        [Location_Descr] => somewhere
        [Start_Date] => 06/03/2002
        [Service_Date] => 06/03/2002
        [Rehire_Date] => 00/00/00
        [Business_Unit] => YYYY
        [Job_Title] => Manager
        [Email] => email@example.com
        [Dept_Desc] => bla bla bla
        [Employee_Name_LF] => Last, First
        [Supervisor_Name_LF] => Last, First
        [Term_Date] => 00/00/00
        [Preferred_Name] => Someone
        [Source] => Sheet2
    )
)

There a several more rows. 还有几行。 The main purpose is to show the results as an HTML table and to generate a CSV file. 主要目的是将结果显示为HTML表格并生成CSV文件。 I already made those functions using the modified structure (the first that I posted). 我已经使用修改后的结构(我发布的第一个)进行了这些功能。 I thought it would be easier to deal with that structure... Indeed it was, but not for sorting unfortunately. 我认为处理这种结构会更容易...的确如此,但不幸的是并非如此。

The array_multisort documentation ( http://php.net/manual/en/function.array-multisort.php ) suggests separating each column as an individual array.. However, as you can see I have several columns (and the user can select more or less to be shown before performing the query.. So I can't just list all of them on the statement). array_multisort文档( http://php.net/manual/en/function.array-multisort.php )建议将每一列分隔为一个单独的数组。但是,如您所见,我有几列(用户可以选择或多或少要在执行查询之前显示。。因此,我不能只在语句中列出所有它们)。

I a willing to change everything just to make the code better to be worked with. 我愿意更改所有内容,只是为了更好地使用代码。

Ugly - would be a lot easier if you formatted the input tables. 丑陋-如果格式化输入表会容易得多。

$arr = array(
  'Employee_ID' => array('1002', '4508', '0002', '1112'),
  'Business_Unit' => array('UER', 'ABC', 'XYZ', 'EER'),
  'LastName' => array('Smith', 'Vicente', 'Simpson', 'Thompson')
);
$employees = array();
foreach (range(0, sizeof($arr[current(array_keys($arr))]) - 1) as $k) {
  $emp = array();
  foreach ($arr as $col => $vals) {
    $emp[$col] = $arr[$col][$k];
  }
  $employees[] = $emp;
}
$sort = array();
foreach ($employees as $k => $v) {
  $sort[$k] = $v['Employee_ID'];
}
array_multisort($sort, SORT_ASC, $employees);
print_r($employees);

And to put back in the original format: 并放回原始格式:

$arr_sorted = array();
foreach (array_keys($arr) as $col) {
  $arr_sorted[$col] = array();
  foreach ($employees as $emp) {
    $arr_sorted[$col][] = $emp[$col];
  }
}
print_r($arr_sorted);

Thank you for posting the extra details in your question, as they did help in understanding the intent of your question. 感谢您发布问题中的其他详细信息,因为它们确实有助于您理解问题的意图。
Now, you didn't tell us how that table should look; 现在,您没有告诉我们该桌子的外观; If you want the employees one per row, or one per column. 如果您希望员工每行一位,或每列一位。 Which is kind of crucial to know. 要知道哪种至关重要。 Normally one would have one employee per line, especially if this is to be exported to CVS. 通常,每条生产线只有一名员工,特别是如果要将其导出到CVS。 However, I have a suspicion that it's the latter you want. 但是,我怀疑是您想要的后者。 Otherwise you've gone about this in a very overly complicated manner. 否则,您将以过于复杂的方式进行处理。

Point in case: Normal one-per-row layout: 以防万一:正常的单行布局:

<?php
$db = new PDO();

// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "e.employee_id, e.first_name, e.lastname, u.business_unit, s.email";

// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$query = <<<outSQL
SELECT {$Fields} FROM `unit` AS u
INNER JOIN `employee` AS e ON e.employee_id = u.unit_id
INNER JOIN `employee` AS s ON s.employee_id = u.supervisor_id
ORDER BY e.`employee_id`
outSQL;

$data = $db->query($query);

// Creating a printf() template for the output, to make the code easier to maintain.
$rowTemplate = <<<outHTML
        <tr>
            <td>%1\$d</td>
            <td>%2\$s</td>
            <td>%3\$s</td>
        </tr>

outHTML;

// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>First name</th>
            <th>Last name</th>
        </tr>
    </thead>
    <tbody>
%s
    </tbody>
</table>
outHTML;

// Regular table output, one employee per line.
$temp = '';
foreach ($data as $e) {
    // hs() is a shortcut function to htmlspecialchars (), to prevent against XSS.
    $temp .= sprintf($rowTemplate, $e['employee_id'], hs($e['first_name']), hs($e['lastname']));
}

// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);

If you want to do it one per column, it becomes a bit more intricate. 如果您想每列执行一次,则它会变得更加复杂。 Though, still a bit easier than your first attempt. 虽然,仍然比您的第一次尝试容易一些。 :) :)
Namely, something like this: 即是这样的:

<?php
$db = new PDO();

// Defining the fields we need here, to avoid having too long a string for the query.
$fields = "employee_id, first_name, lastname";

// Do the sorting in the database itself. Not only is this faster, but it
// is also a lot easier to sort it exactly as you'd like.
// Note that I don't use prepared statements here, as there is no user-input.
$data = $db->query("SELECT {$Fields} FROM `employees` ORDER BY `employee_id`");

// We need to know how many columns we'll have. One per employee.
$columns = count ($data);

// Rows have a header in front of each line, and one td tag for each employee.
$rowTemplate = "\t\t<th>%s</th>\n".str_repeat("\t\t\t<td>%s</td>\n", $columns);

// Generate the table template, using placeholders for where the data will be added..
$tableTemplate = <<<outHTML
<table>
    <tbody>
%s
    </tbody>
</table>
outHTML;

// Reformat the array to give us the data per-column.
$temp = array ();
foreach ($data as $field => $e) {
    // Since we've already sorted the data in the database we don't need to do any further sorting here.
    // Also note that I'm doing the escaping here, seeing as this array will only be used for output.
    $temp['Employee ID'][] = intval($e['employee_id']);
    $temp['First name'][] = hs($e['first_name']);
    $temp['Last name'][] = hs($e['lastname']);
}

// Now we do the same as in the above example.
$rows = '';
foreach ($temp as $label => $l) {
    // We have the label as the first template variable to be added, so put it as the first element.
    array_unshift($l, $label);

    // Add the current row of items to the output, using the previously established template.
    $rows = vprintf($rowTemplate, $l);
}

// Add the rows to the table, so that you can echo the completed product wherever you need.
$employeeTable = sprintf($tableTemplate, $temp);

PS: Haven't tested the code, but it should work. PS:尚未测试代码,但应该可以。

I ran into his problem and after much angst found a really nice solution in the notes on the php manual page - I now have the following function which i use whenever I need to solve this type of problem. 我遇到了他的问题,并且在许多烦恼之后,在php手册页的注释中找到了一个非常不错的解决方案-我现在有以下功能,可以在需要解决此类问题时使用。

function fnArrayOrderby(){
//function to sort a database type array of rows by the values in one or more column
//source http://php.net/manual/en/function.array-multisort.php - user notes
//example of use -> $sorted = fnArrayOrderby($data, 'volume', SORT_DESC, 'edition', SORT_ASC);

$args = func_get_args(); //Gets an array of the function's argument list (which can vary in length)
//echo "sorting  ".$args[0]."<br>";
if (!isset($args[0])) { return;}
$data = array_shift($args); //Shift an element off the beginning of array
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM