【问题标题】:search within array for last 7 occurrences在数组中搜索最后 7 次出现
【发布时间】:2012-02-16 21:24:48
【问题描述】:

我正在编写一个 php 代码来搜索文本文件中的不同变量....

数据在平面文件中逐行列出,数据列表格式为:

date | time | ip | geo-location (city) | //url

数据保存为日志文件('track-log.txt')

我目前的代码是:

$log_file = file_get_contents('track-log.txt');

$log_lines = explode(PHP_EOL, $log_file);

$log_lines = array_flip($log_lines);

unset($log_file);

这会将文本文件分成几行,然后将这些行向后翻转,以便它们在数组 $log_lines[*] 中作为文本文件的最后一行列出,首先显示为 $log_lines[0]

我需要计算有多少次“日期”是相同的......

<..... lots of logs here .... then .....>

jan 1st 2012 | data.....
jan 1st 2012 | data ....
jan 1st 2012 | data ....
jan 1st 2012 | data ....
jan 1st 2012 | data ....
jan 2nd 2012 | data ....
jan 2nd 2012 | data ....
jan 2nd 2012 | data .... <end log>

想象这是日志的结尾......我想:

$count[0] = 3 // last 3x dates are the same
$count[1] = 5 // the 5x dates before that are the same

所以我可以使用

echo $count[0];

在日志的“日期”部分显示最新值的数量。

我希望数组 $count[*] 停止列出 @ 7 个字符串....

$count[0]; ... 最多 ... $count[6]

这将显示最近 7 天的日志页数

....

extra info....日志中每一行的日期格式是

sunday, january 22, 2012 | 16:14:36 | 82.**.***.*** | bolton | //page_url

而且日期格式始终是一样的,因为它是一个脚本,在每个日志行上写入每个日期

....

【问题讨论】:

  • 您的启动代码不正确。 array_flip 交换键和值。您只需要$lines=file('track-log.txt'); $lines=array_reverse($lines);
  • 我需要explode命令,逐行分割主输入字符串.....除非你有更好的编码方式......?
  • file() 函数为您提供了一系列行。不需要explode()

标签: php arrays search flat-file


【解决方案1】:

这是解决问题的实用方法。

$lines = file('track-log.txt');

// This is a group discriminator
// It must return a 'key' which is what to group by,
// (in this case, by column 1 of the input line).
// as well as the orginal value.
function col1group($line){
    $key = trim(current(explode('|', $line, 2)));
    return array($key=>$line);
}

// $grouper is the group-descriminator function.
// we generate a new array with our keys to group by, then group them by
// key with array_merge_recursive
function array_groupby($array, $grouper) {
    return call_user_func_array('array_merge_recursive', array_map($grouper, $array));
}

//This is all lines, in file order, grouped by date.
$linesbydate = array_groupby($lines, 'col1group');

// if you want just the last seven:
$last7dates = array_slice($linesbydate, -7);
// if you want numeric keys:
$last7groups = array_values($last7dates);
// if you want them in reverse order:
$last7groupsReversed = array_reverse($last7groups);

// desired output
var_dump($last7groupsReversed);

使用你给这个程序的示例行将输出:

array(2) {
  [0]=>
  array(3) {
    [0]=>
    string(25) "jan 2nd 2012 | data ....
"
    [1]=>
    string(25) "jan 2nd 2012 | data ....
"
    [2]=>
    string(25) "jan 2nd 2012 | data ....
"
  }
  [1]=>
  array(5) {
    [0]=>
    string(25) "jan 1st 2012 | data.....
"
    [1]=>
    string(25) "jan 1st 2012 | data ....
"
    [2]=>
    string(25) "jan 1st 2012 | data ....
"
    [3]=>
    string(25) "jan 1st 2012 | data ....
"
    [4]=>
    string(25) "jan 1st 2012 | data ....
"
  }
}

如果您需要按其他标准进行分组,您可以通过创建另一个函数(如 col1group())并将其传递给 array_groupby() 来实现。您还可以在此函数中更改行本身(例如,调用 rtrim() 删除换行符)。

【讨论】:

  • 嗨弗朗西斯我设置了错误列表,但是当我使用你的代码时,我只是得到一个空白页?对不起
  • 这里没有问题。我已将我的输出附加到答案中。你至少看懂代码了吗?
  • 是的,我理解代码,但它不起作用,但这个问题的其他答案之一起作用了,我现在已经完成了今天的脚本.....我可能也会开始下一个 tonite 的工作哈哈,无论如何,谢谢队友
【解决方案2】:

这应该是诀窍......

<?php

$log_file = file_get_contents('track-log.txt');
$log_lines = explode(PHP_EOL, $log_file);
$log_lines = array_reverse($log_lines);
unset($log_file);
$count = array();
//loop through and itterate the count array using the date as the unique key
foreach($log_lines as $line){
    //explode this so we can use the date segment as a key
    $pieces = explode('|',$line);
    if (!isset($count[$pieces[0]])){
        //break out if we've hit the cap size
        if (count($count)>=7){break;}
        $count[$pieces[0]] = 0; 
    }
    $count[$pieces[0]]++;

}
//switch to a numeric index
$count = array_values($count);

?>

【讨论】:

  • 你只计算7天一次,即使它有5次
  • 很好的捕捉 rauschen。我已经进行了相应的编辑(将中断条件移动到元素创建步骤中。
  • 该死!!我已经编辑了第一个版本以删除它!再次感谢:)
  • 编码的小问题....作为写入数据行的脚本先写入数据,然后是换行符,您编写的脚本将 $count[0] 计为空行,并列出值“1” .... 将 (count($count)>=7) 更改为 8,并错过了数组 $count[0] ,只需使用 1 - 7 即可,非常感谢
  • 您还可以 trim() 日志内容以删除尾随/前导行。很高兴它正在工作
【解决方案3】:

该函数更改键和值并且不反转数组..

 $log_lines = array_flip($log_lines);

这样做

$log_lines = array_reverse($log_lines);

生成计数数组

$count = array();
$index = -1;
$last_date = false;
foreach ($log_lines as $lines) {
     //sunday, january 22, 2012 | 16:14:36 | 82.**.***.*** | bolton | //page_url
     list($date,) = explode("|",$lines,2); //extract date 

     if ($last_date == $date)
          $count[$index]++;
     else {
         $last_date = $date;
         $index++;
         if ($index>=7) break; // 8. Date -> break
         $count[$index] = 1;
     }
}

【讨论】:

  • +1 to rauchen 用于 (a) 首先捕获 array_reverse 错误,(b) 在我和 Leonard 的原始答案中捕获过早中断子句,以及 (c) 在 explode 子句中使用 limit 参数 (这在优化方面可能有点矫枉过正,但仍然是一种很好的做法,并且对于具有长日志条目的平面文件可能会有所作为)。我仍然更喜欢我的方法(直接使用日期作为唯一键,然后在最后使用 array_value-ing),但这同样好,也是一个更好的整体答案。
猜你喜欢
  • 1970-01-01
  • 2015-06-06
  • 2023-03-28
  • 2021-05-28
  • 2010-12-11
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多