LINUX.ORG.RU

Perl -> Python

 ,


0

2

Многоуважаемый all,

вот сижу, ломаю голову, как нижеприведённый код покрасивее реализовать на на Python

my @arr = ();
#          [  0  ,  1  ,   2   ,   3  ]
push @arr ,[$time,$host,$status,$bytes];
  my %reqs_host;
  my %bytes_host;
  my %errors_host;
  foreach(@arr){  
    $reqs_host{$_->[1]}++;
    $bytes_host{$_->[1]} += $_->[3];
    $errors_host{$_->[1]}++ if $_->[2] =~ /^[45]/;
  }

А в чём трудности? Код простой. Массивы и ассоциативные массивы в питоне есть. Безымянную переменнюу никто не мешает заменить на именованную

router ★★★★★ ()
Ответ на: комментарий от Virtuos86

просто я думал что это 2 наипопулярнейших языков здешних завсегдатаев...

как я это понимаю:

есть массив состоящий из списков - ($time,$host,$status,$bytes)ю (...), (...)
скажем это лог клиентов веб сервера.

этот цикл подсчитывает сколько раз засветился один и тот же $host (инкрементирует счётчик в соответствующем словаре), сколько байт скачал $host, также считает сколько ошибок получил этот хост.

Выгляди изящно, на Python тоже должно быть как-то так, только пока не придумал как именно :)

Den0k ()
Ответ на: комментарий от router

проблема в том, что я не до конца понимаю даже этот цикл на Perl

можно пример? Хотя бы с инкрементацией числа повторений $host.

Den0k ()
Ответ на: комментарий от Den0k

foreach(@arr){

В цикле проходим по всем элементам массива @arr. Текущий рассматриваемый элемент помещается в безымянную переменную $_

А из кода чуть выше мы знаем, что каждый из элементов массива представляет из себя ссылку на хэш ( ассоциативный массив ) , т.е. $_ = ['time_i', 'host_i', 'status_i', 'bytes_i' ]

$reqs_host{$_->[1]}++;

-> - операция разыменования ссылки, т.е. $_->[1] есть первый ( напоминаю, нумерация с нуля ) элемент из массива, на который ссылается $_. Для примера выше, $_->[1] = 'host_i'

Т.е. в хеше %reqs_host ищется элемент 'host_i', и его значение увеличивается на 1. Если такого элемента не было, он автоматом создаётся

$bytes_host{$_->[1]} += $_->[3];

то же самое

$errors_host{$_->[1]}++ if $_->[2] =~ /^[45]/;

выполним $errors_host{$_->[1]}++ в том случае, если поиск по регулярному выражению нашёл совпадение. Другими словами

if ( $_->[2] =~ m/^[45]/ ) { $errors_host{$_->[1]}++ }

router ★★★★★ ()
Ответ на: комментарий от router

З.Ы. для понимания текущей ситуации в perl есть такой трюк:

use Data::Dumper;

printf "%s\n", Dumper( $var1 );
printf "%s\n", Dumper( \@var2 );
printf "%s\n", Dumper( \%var2 );

Попробуй, тебе понравится

router ★★★★★ ()
Ответ на: комментарий от router

А из кода чуть выше мы знаем, что каждый из элементов массива представляет из себя ссылку на хэш ( ассоциативный массив )

Прошу прощения, не на хэш, а на обычный массив. На дальнейшее объяснение эта ошибка не влияет

router ★★★★★ ()
Ответ на: комментарий от router

router, спасибо, теперь мне полностью понятен этот Perl код, примерно так и думал, просто ты сформулировал предельно чётко. Не знал что хэш ( ассоциативный массив ) это просто dictionary.

Мне осталось написать это на Python.

Den0k ()
Ответ на: комментарий от router

да, а то опыт с perl -d не очень помог. почему-то привычный метод вставлять print в нужных местах не давал результата, но это был какой-то локальный глюк.

Den0k ()
from re import match
from collections import Counter

arr = [(0, 1, 2, 3), (5, 6, 7, 8)]

reqs_host = Counter()
bytes_host = Counter()
errors_host = Counter()

for item in arr:
    reqs_host[item[1]] += 1
    bytes_host[item[1]] += item[3]

    if match('^[45]', str(item[2])):
        errors_host[item[1]] += 1

но это транслитерация один-в-один, а не идиоматический питон.

val-amart ★★★★★ ()
Ответ на: комментарий от Den0k

есть массив состоящий из списков - ($time,$host,$status,$bytes)ю (...), (...)

Кортежей штоле? Так коротко, как в Перле, не получится, но как-то так:

reqs_host, bytes_hosts = {}, {}
reqs_host.setdefault(0)
bytes_host.setdefault(0)
for _, hostname, bytes, _ in arr:
  reqs_host[hostname] += 1
  bytes_host[hostname] += bytes
  # про =~ хз - не знаю, что это
tailgunner ★★★★★ ()
Последнее исправление: tailgunner (всего исправлений: 2)
Ответ на: комментарий от Den0k

Теперь понятно зачем придумали питон.

anonymous ()
Ответ на: комментарий от tailgunner

ух ты, setdefault это круто, не знал про такое. а ~= это матчинг регулярки.

val-amart ★★★★★ ()

Тред-детектор неосиляторов перла ;]

grouzen ★★ ()
arr = [
	(1, 1, 'hello5', 4),
	(1, 2, '5world', 5),
]

import re

class CounterDict(dict):
	def increment(self, key, value):
		self[key] = self.get(key, 0) + value

reqs_host = CounterDict()
bytes_host = CounterDict()
errors_host = CounterDict()

for (time, host, status, bytes) in arr:
	reqs_host.increment(host, 1)
	bytes_host.increment(host, bytes)
	errors_host.increment(host, 1 if re.match(r'^[45]', status) else 0)
kvap ()

Нет смысла в данном случае пихать в главный массив анонимные массивы. Первое, они жрут память. Второе, разыменовывание массива не есть гуд.

push @all, $time, $host, $status, $bytes;
# Note:
#   $time is never used

# next variables will be used later (after loop)
my %reqs_host;
my %bytes_host;
my %errors_host;

{
  my $host;
  my $status;
  my $bytes;

  while (@all) {
    (undef, $host, $status, $bytes) = splice @all, 0, 4;
    $reqs_host{$host}++;
    $bytes_host{$host} += $bytes;
    $errors_host{$host}++ if $status =~ /^[45]/;
  }
}

# do something
printf "Total hosts: %d\n", scalar keys %reqs_host;
...

gh0stwizard ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.