SpencerX
SpencerX

Reputation: 5733

Parse multiline text and sort array rows by time range expressions

I have an array $session that I extract from an awstats file:

# Session range - Number of visits
BEGIN_SESSION 7
1h+ 10
5mn-15mn 9
0s-30s 107
2mn-5mn 7
30s-2mn 21
15mn-30mn 4
30mn-1h 11
END_SESSION

First I wanted to rearrange this by adding the two values of 0s-30s & 30s-2mn and creating another one, here's how I tried it:

$newline = "\n";
$lines = explode($newline, $session);
$results = array();
foreach ($lines as $line) {
     $parts = explode(" ", trim($line), 2);
     if (count($parts) < 2)
         continue;
     else {
         $results[$parts[0]] = intval($parts[1]);
     }
}

$temp['0s-30s'] = (isset($results['0s-30s']) ? $results['0s-30s'] : NULL);
$temp['30s-2mn'] = (isset($results['30s-2mn']) ? $results['30s-2mn'] : NULL);
$results['0s-2mn'] = $temp['0s-30s'] + $temp['30s-2mn'];
unset($results['0s-30s'], $results['30s-2mn']);
$session = $results['BEGIN_SESSION'] . $newline;
foreach ($results as $k => $v)
    $session .= $k . " " . $v . $newline;
$session .= "END_SESSION";


$session = explode("\n", $session); 
unset($session[(count($session) - 1)]); 
unset($session[0]); 
unset($session[1]);
$sessions = array();

foreach ($session as $key => $value) {
    $session[$key] = explode(" ", $value);
    $sessions[] = array($session[$key][0], trim($session[$key][1])); 
}

and it displays me this array :

Array
(
    [0] => Array
        (
            [0] => 1h+
            [1] => 10
        )

    [1] => Array
        (
            [0] => 5mn-15mn
            [1] => 9
        )

    [2] => Array
        (
            [0] => 2mn-5mn
            [1] => 7
        )

    [3] => Array
        (
            [0] => 15mn-30mn
            [1] => 4
        )

    [4] => Array
        (
            [0] => 30mn-1h
            [1] => 11
        )

    [5] => Array
        (
            [0] => 0s-2mn
            [1] => 128
        )

)

Is there a way to rearrange my array like this:

Array
(
    [0] => Array
        (
            [0] => 1h+
            [1] => 10
        )

    [1] => Array
        (
            [0] => 30mn-1h
            [1] => 11
        )

    [2] => Array
        (
            [0] => 15mn-30mn
            [1] => 4
        )

    [3] => Array
        (
            [0] => 5mn-15mn
            [1] => 9
        )

    [4] => Array
        (
            [0] => 2mn-5mn
            [1] => 7
        )

    [5] => Array
        (
            [0] => 0s-2mn
            [1] => 128
        )

)

Note: $session sometimes come with missing sessions.

Upvotes: 0

Views: 79

Answers (2)

mickmackusa
mickmackusa

Reputation: 47991

The sorting is made simple by parsing the the leading integer and its following letter for later use in array_multisort() -- these characters will be enough to determine a big-endian sort. Any lines which do not contain all four needed substrings will be excluded from the result.

array_multisort() will sort by leading unit letter ASC (h before m before s), then by leading time integer DESC. Demo

$results = [];
foreach ($lines as $line) {
    if (sscanf($line, '%d%1s%s %d', $time, $unit, $tail, $count) === 4) {
        $times[] = $time;
        $units[] = $unit;
        $result[] = ["$time$unit$tail", $count];
    }
}
array_multisort($units, $times, SORT_DESC, $result);
var_export($result);

Upvotes: 0

Brian Adams
Brian Adams

Reputation: 1090

<?php

$session = 'BEGIN_SESSION 7
1h+ 10
5mn-15mn 9
0s-30s 107
2mn-5mn 7
30s-2mn 21
15mn-30mn 4
30mn-1h 11
END_SESSION';

$newline="\n";
$lines = explode($newline,$session);
$results = array();

foreach($lines as $line) {
    $parts = explode(" ", trim($line), 2);
    if (in_array($parts[0], array('BEGIN_SESSION', 'END_SESSION'))) continue;
    else $results[$parts[0]] = intval($parts[1]);
}

$temp['0s-30s'] = isset($results['0s-30s']) ? $results['0s-30s'] : 0;
$temp['30s-2mn'] = isset($results['30s-2mn']) ? $results['30s-2mn'] : 0;
$results['0s-2mn'] = $temp['0s-30s'] + $temp['30s-2mn'];
unset($results['0s-30s'], $results['30s-2mn']);

$order = array('0s-2mn', '2mn-5mn', '5mn-15mn', '15mn-30mn', '30mn-1h', '1h+');

uksort($results, function($a, $b) use ($order) {
    return array_search($a, $order) < array_search($b, $order);
});

var_dump($results);

Upvotes: 1

Related Questions