【问题标题】:Sort array by non-alphabetical, user defined string values按非字母、用户定义的字符串值对数组进行排序
【发布时间】:2018-04-16 22:53:39
【问题描述】:

我想以复杂的方式对数组进行排序,但不知道该怎么做。以下是我正在处理的数据的粗略概念:

[
  { target: random.text.cpu-pct-0, otherData[...] },
  { target: random.text.cpu-pct-1, otherData[...] },
  { target: random.text.cpu-pct-2, otherData[...] },
  { target: random.text.example-0, otherData[...] },
  { target: random.text.example-1, otherData[...] },
  { target: random.text.memory, otherData[...] },
  ...
]

我希望所有带有 target 且包含字符串 cpu-pct 的对象排在第一位,然后是带有 target 且包含字符串 memory 的对象,然后是 example。这个数组可以有任意数量的项目,所以按索引重新排序是行不通的。可能有 1 个带有 target 的对象,其中包括 cpu-pct,或者可能有 50 多个。我排序的其他字符串也是如此。

我考虑循环遍历原始数组,检查是否存在所需的字符串,将匹配的对象保存到我正在寻找的每个目标的新数组中,然后在最后合并数组。我认为这可行,但我想有一个更好、更有效的解决方案,可能使用usort,但我不知所措。有什么想法吗?

【问题讨论】:

  • 那么这个cpu-pct-0应该出现在这个cpu-pct-1之前吗? target 是否总是包含 cpu-pctmemeryexample 之一?
  • 使用php.net/manual/en/function.usort.php 创建自定义排序比较函数您可以在一个函数中轻松定义规则。在比较两个项目时,此函数应返回 -101 作为其响应。该页面中的示例将有所帮助。先试试这个,然后随意发布第二个问题,其中包含您的代码尝试示例。
  • @fubar 是的,cpu-pct-0 应该先出现,然后按照最后的数字升序排列。忘了提,但也会有一个cpu-pct-avg,它应该出现在其他cpu-pct 值之后

标签: php php-5.4 usort


【解决方案1】:

usort 绝对是要走的路。这是一种相当通用的方法,您可以扩展 $ranks 数组以包含其他术语以根据需要进行排序。

$a = json_decode('[
  { "target": "random.text.cpu-pct-0", "otherData": [1, 2, 3] },
  { "target": "random.text.cpu-pct-1", "otherData": [2, 2, 3] },
  { "target": "random.text.cpu-pct-2", "otherData": [3, 2, 3] },
  { "target": "random.text.example-0", "otherData": [4, 2, 3] },
  { "target": "random.text.example-1", "otherData": [5, 2, 3] },
  { "target": "random.text.memory", "otherData": [6, 2, 3] } ]');

$ranks = array('example' => 0, 'memory' => 1, 'cpu-pct' => 2);

function rank($obj) {
    global $ranks;

    foreach ($ranks as $key => $value) {
        if (strpos($obj->target, $key) !== false) return $value;
    }
    // sort anything that doesn't match last
    return -1;
}

function cmp($a, $b) {
    return rank($b) - rank($a);
}

usort($a, "cmp");

print_r($a);

输出:

Array
(
    [0] => stdClass Object
        (
            [target] => random.text.cpu-pct-0
            [otherData] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 3
                )

        )

    [1] => stdClass Object
        (
            [target] => random.text.cpu-pct-1
            [otherData] => Array
                (
                    [0] => 2
                    [1] => 2
                    [2] => 3
                )

        )

    [2] => stdClass Object
        (
            [target] => random.text.cpu-pct-2
            [otherData] => Array
                (
                    [0] => 3
                    [1] => 2
                    [2] => 3
                )

        )

    [3] => stdClass Object
        (
            [target] => random.text.memory
            [otherData] => Array
                (
                    [0] => 6
                    [1] => 2
                    [2] => 3
                )

        )

    [4] => stdClass Object
        (
            [target] => random.text.example-0
            [otherData] => Array
                (
                    [0] => 4
                    [1] => 2
                    [2] => 3
                )

        )

    [5] => stdClass Object
        (
            [target] => random.text.example-1
            [otherData] => Array
                (
                    [0] => 5
                    [1] => 2
                    [2] => 3
                )

        )

)

如果您想进一步对关键字后面的值进行排序,您可以将其附加到排名值,然后对组合值进行排序,例如

$ranks = array('cpu-pct', 'memory', 'example');

function rank($obj) {
    global $ranks;

    foreach ($ranks as $key => $value) {
        if (preg_match("/$value(.*)$/", $obj->target, $matches))
            return $key . $matches[1];
    }
    // sort anything that doesn't match last
    return 'z';
}

function cmp($a, $b) {
    return strcmp(rank($a), rank($b));
}

usort($a, "cmp");

如果要排序的字符串超过 10 个,则需要将返回值从 rank 更改为 sprintf('%02d', $key) . $matches[1] 以确保排序正常进行(将 02 替换为尽可能多的数字以确保您可以代表所有这么多位数的排序字符串)。

【讨论】:

  • 这是一个很好的解决方案,大部分时间都在为我工作。有没有办法确保所有cpu-pct 值按升序排列(cpu-pct-0cpu-pct-1cpu-pct-2 等),然后让cpu-pct-avg 紧随其后?现在这些都分组在一起,但不是按照我想要的顺序。 cpu-pct 组之后的其他项目排序正确。
  • 嗨,布雷特,我已经用一个函数更新了答案,该函数也会对字符串的尾随部分进行排序。请注意,这实际上取决于您的数据格式,如果您想要更复杂,您需要根据@Scuzzy 的答案做一些事情。
【解决方案2】:

这是一种排序方法,您必须为希望排序的每个可能组合定义条件。希望我的代码 cmets 能给你一个关于方法的提示。

$array = json_decode('[
  { "target": "random.text.cpu-pct-0" },
  { "target": "random.text.cpu-pct-1" },
  { "target": "random.text.cpu-pct-2"},
  { "target": "random.text.example-0" },
  { "target": "random.text.example-1" },
  { "target": "random.text.memory" }
]');

function mySortFunction( $one, $two )
{

  $pattern = '/\.(?<label>cpu-pct|example|memory)(?:-(?<value>\d+))?/';
  preg_match( $pattern, $one->target, $targetOne );
  preg_match( $pattern, $two->target, $targetTwo );

  // Both have CPU-PCT? then sort on CPU-PCT-VALUE
  if( $targetOne['label'] === 'cpu-pct' and $targetTwo['label'] === 'cpu-pct' )
  {
    return strcmp( $targetOne['value'], $targetTwo['value'] );
  }
  // Both have MEMORY? they are the same
  if( $targetOne['label'] === 'memory' and $targetTwo['label'] === 'memory' )
  {
    return 0;
  }
  // 1 has CPU but 2 has Memory, prefer CPU
  if( $targetOne['label'] === 'cpu-pct' and $targetTwo['label'] === 'memory' )
  {
    return -1;
  }
  // 1 has MEMORY but 2 has CPI, prefer CPU
  if( $targetOne['label'] === 'memory' and $targetTwo['label'] === 'cpu-pct' )
  {
    return 1;
  }
  // 1 is MEMORY or CPU, but 2 is Neither
  if( $targetOne['label'] === 'cpu-pct' or $targetOne['label'] === 'memory' )
  {
    if( $targetTwo['label'] !== 'cpu-pct' and $targetTwo['label'] !== 'memory' )
    {
      return -1;
    }
  }
  // 2 is MEMORY or CPU, but 1 is Neither
  if( $targetTwo['label'] === 'cpu-pct' or $targetTwo['label'] === 'memory' )
  {
    if( $targetOne['label'] !== 'cpu-pct' and $targetOne['label'] !== 'memory' )
    {
      return 1;
    }
  }
  // ETC
  // ETC
  // ETC
}

usort( $array, 'mySortFunction' );

【讨论】:

    猜你喜欢
    • 2013-06-11
    • 1970-01-01
    • 2011-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    相关资源
    最近更新 更多