LINUX.ORG.RU
ФорумTalks

С уделал Python по скорости разработки ;)

 , ,


0

2

Короче, мне надо было сделать следующее. Считать из ASCII-файла с вещественными числами ровно N чисел, причём эти числа идут в файле через пробел и иногда происходит перевод строки, типа такого:

1.45E+4 5E+6 7E+8
2.42E+1 7.7E+2 1E-1 5E-6 4E-6
1E-6 1E-8
.....
Этих чисел в файле M, M ~ 1E+7, N ~ 1E+6

Люблю Python, полез в инет выяснять, как это сделать на нём - везде пример с чтением файла построчно и потом разбор строки. Плюнул и написал прогу на C за пару минут

Eddy_Em, твоя взяла - Python отстой, C рулит :)

Если кто знает, как это сделать в Python без чтения построчно - пишите

Update: размер файла - порядка 24Гигов, надо вывести N-ое число (а не все N чисел)

★★★★☆

Последнее исправление: Sahas (всего исправлений: 1)
Ответ на: комментарий от drull

Не тупите. Человек спросил, правильно ли он понял, что loadtxt возвращает список, значения из которого можно получать по индексам. Я ответил, что нет, не список, но да, можно. Если бы ТС предполагал мерность >1, он бы не ждал, что list[i] вернёт число.

Axon ★★★★★
()
Последнее исправление: Axon (всего исправлений: 1)
print open("ascii-file").read().replace("\n", " ").split(" ", N + 1)[-2]

Но, учитывая размеры файла, этот код просто зависнет :).

N = ...

with open("ascii-file") as f:
    t = 0
    while t < N:
        slice = 10
        while True:
            data = f.read(slice).replace("\n", " ")
            if data.find(" ") == -1:
                slice += 10
                continue
            else:
                data = data.split(" ", 1)[0]
                break
        f.seek(f.tell() + len(data) + 1)
        
        t += 1
    else:
        print data

Без регулярок, лень вспоминать. upd. Поправил. Пока дописывал конец кода, забыл его начало.

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от Sahas

LOR мельчает

на С никто не предложил strtok, strspn или сразу заюзать flex; (hint - N-ное число идёт сразу за разделителем ([ \t\n]+))

нет вариантов на обожаемых lisp, haskell

а ведь уже третья страница треда..

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

ты назвал последовательность из N элементов , массивом размерности N

всё ок. все тебя поняли.

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

Не знаю. Я не тестил, по идее алгоритм верный. Мне бы тестовый файлик в миниатюре. А долго работает, потому что и должен долго работать, зато экономно.

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

Тогда вот посимвольно:

file=__ФАЙЛ_С_ЧИСЛАМИ__
result=N
numInt=0
symInt=0
while IFS= read -n 1 sym; do
    if [[ "$sym" == ' ' ]] || [[ "$sym" == '' ]]; then
        numInt=$((++numInt))
        if [[ "$numInt" == "$result" ]]; then
            echo "$num"
            break 3
        else
            num=
        fi
    else
        num="$num$sym"
    fi
done < "$file"

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 1)
Ответ на: комментарий от Darth_Revan

более 20 мин работало, не дождался окончания...

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

кстати, чтение заняло около 15 минут.

Посмотри на код, там ищется и считывается каждое число; естественно, это не быстро.

N = ...

with open("ascii-file") as f:
    counter = 0
    while counter < N:
        slice = 10
        while True:
            chunk = f.read(slice).replace("\n", " ")
            if chunk.find(" ") == -1:
                slice += 100
                f.seek(-len(chunk))
                continue
            else:
                number = chunk.split(" ", 1)[0]
                break
        f.seek(len(number) - len(chunk) + 1, 1)
        
        counter += 1
    else:
        print number
Ошибка была в моем непонимании работы с файлами :(.

Virtuos86 ★★★★★
()

Update: размер файла - порядка 24Гигов, надо вывести N-ое число (а не все N чисел)

Этих чисел в файле M, M ~ 1E+7, N ~ 1E+6

ну как было можно добиться, что при N всего-то 1E+6 более 20 мин работало, не дождался окончания... получается больше 0,0012сек/число, то есть или руки сильно кривые, или никуда не годный инструмент..

даже на tcl, с его не шибко эффективным компилятором 8 млн.ная запись вытаскивается очень быстро.

#!/usr/bin/tclsh

# return N-th word from file passed by name
proc Nth_word { N fname } { 
	set len 0
	set f [ open $fname "r" ]
	while { ! [ eof $f ] } {
		set line [ gets $f ]
		set nlen [ expr {$len + [ llength $line ] } ]
		if { $N<$nlen } {
			close $f
			return [ lindex $line [ expr { $N - $len } ] ]
		}
		set len $nlen
	}
	close $f
	return {}
}
if { [ llength $argv ] != 2 } {
	puts stderr "Usage: $argv0 N filename"
	exit 1
}

set tm [ time {
	puts [ Nth_word {*}$argv ]
} ]

puts stderr $tm

на С подобное считается вообще практически со скоростью чтения файла.

MKuznetsov ★★★★★
()

java

Path filePath = Paths.get("file.txt");
Scanner scanner = new Scanner(filePath);
int i = 0;
result = 0;
while (i<N && scanner.hasNext()) {
    if (scanner.hasNextInt()) {
        result = scanner.nextInt();
        i++;
    } else {
        break;
    }
}
stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: LOR мельчает от MKuznetsov

сразу заюзать flex

Да, и правда. Исправим ситуацию. flex-быдлокод (в духе 70-х, с глобальными переменными)

%{
unsigned int line_num = 1;
unsigned int n = 0, limit = 0;
double f = 0;
%}

%option noyywrap

FNUM    [-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?

%%
     
{FNUM}		{
			n++;
			if (n == limit) {
				f = atof(yytext);
				return;
			} 
		}

[\n]		line_num++;

[ \t]+		/* eat up whitespace */
     
.		printf("Unrecognized character: %s at line %d\n", yytext, line_num);
     
%%
     
int
main(int argc, char **argv)
{
	if (argc != 3) {
		fprintf(stderr, "Usage: %s file n\n", argv[0]);
		return 1;
	} else {
		yyin = fopen(argv[1], "r");
		limit = atoi(argv[2]);
		if (limit == 0) {
			fprintf(stderr, "Invlid n: '%s'\n", argv[2]);
			return 1;
		}
	}
     
	yylex();
	if (n != limit) {
		fprintf(stderr, "Can't get element #%u\n", limit);
		return 1;
	}
	printf("f: %f\n", f);
	return 0;
}

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

ну как было можно добиться, что при N всего-то 1E+6 более 20 мин работало, не дождался окончания... получается больше 0,0012сек/число, то есть или руки сильно кривые, или никуда не годный инструмент..

штука в том, что на самом деле ищется запись с N~108E+6 из M~1E+9, просто, когда я писал пост, я на числа не посмотрел... =)

Sahas ★★★★☆
() автор топика
Последнее исправление: Sahas (всего исправлений: 1)
Ответ на: комментарий от Sahas

Мм... ну да. Для скорости можно Pypy заюзать, но на C все равно быстрее будет. Вот вроде работающий вариант:

#!/usr/bin/env python
# encoding: utf-8

import sys
from shlex import shlex

s = shlex(open(sys.argv[1]))
s.wordchars = '0123456789.+-eE'

for i in range(int(sys.argv[2])):
    s.get_token()

print(s.get_token())
ei-grad ★★★★★
()
Последнее исправление: ei-grad (всего исправлений: 3)
Ответ на: комментарий от Virtuos86

Ять, ошибочка. Вместо

f.seek(-len(chunk))

должно быть

f.seek(-len(chunk), 1)

Virtuos86 ★★★★★
()
#lang racket

(define (find-num n)
  (call-with-input-file "numbers"
    (λ (file)
       (let loop ([i n])
         (define number (car (regexp-match #px"\\S+" file)))
         (match i
           [1 number]
           [_ (loop (sub1 i))])))))
qweqwe
()
Ответ на: LOR мельчает от MKuznetsov

нет вариантов на обожаемых lisp, haskell

Да даже на плюсах не написали

#include <iostream>
#include <fstream>
#include <cstdlib>

int
main (int argc, char **argv)
{
  std::fstream fin (argv[1], std::fstream::in);
  double answer;
  
  for (int i = 0; i < std::atoi (argv[2]); i++)
    fin >> answer;
  fin.close ();

  std::cout << answer << std::endl;
  return 0;
}
kim-roader ★★
()
Ответ на: комментарий от Sahas

на C я это сделал так:

 f=fopen("ascii-file","r");

  for (i=0;i<N;i++)
  {
    fscanf(f,"%g ",&num);
  }
  printf("%lg\n",num);

когда данных много (а их у вас действительно много), в scanf`е надо использовать '*' для полей которые ненужны, это процентов на 15-20 быстрее работает, внутри scanf есть соотв.оптимизации. то есть с мелким фиксом работать будет уже шустрее:

 f=fopen("ascii-file","r");

  for (i=0;i<N-1;i++)
  {
    if (fscanf(f,"%*g")!=0) { /** eof or not double?? **/};
  }
  fscanf(f,"%g",&num);
  printf("%lg\n",num);

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

в scanf`е надо использовать '*' для полей которые ненужны

спасибо, буду знать

Sahas ★★★★☆
() автор топика
Ответ на: комментарий от qweqwe

Куда ж рэкетирам без контрактов c тестами :)

#lang at-exp racket

(define/contract ((find-num n) in-prt)
  (exact-positive-integer? . -> . (input-port? . -> . number?))
  (let loop ([i (sub1 n)])
    (define p (regexp-match #px"\\S+" in-prt))
    (unless p
      (error 'find-num "eof!"))
    (if (zero? i)
        (string->number (bytes->string/utf-8 (car p)))
        (loop (sub1 i)))))

(module+ test
  (require rackunit)
  (define txt @~a{1.45E+4 5E+6 7E+8
                  2.42E+1 7.7E+2 1E-1 5E-6 4E-6
                  1E-6 1E-8})
  (define (test-helper n)
    (call-with-input-string txt (find-num n)))
  (check-equal? (test-helper 9) 1e-6)
  (check-exn exn:fail? (λ () (test-helper 100) 1e-6)))

(call-with-input-file "numbers.txt" (find-num N))
qaqa ★★
()
Последнее исправление: qaqa (всего исправлений: 1)
Ответ на: комментарий от qaqa

Почему в Talks?

флейма ради. Задачка-то не сильно техническая :)

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