Как я могу объединить файлы в один файл CSV? - PullRequest
0 голосов
/ 13 июля 2009

Если у меня есть один файл FOO_1.txt, который содержит:

FOOA

FOOB

FOOC

FOOD

...

и много других файлов FOO_files.txt. Каждый из них содержит:

1110000000 ...

одна строка, содержащая 0 или 1 в качестве числа FOO1 значений (fooa, foob, ...)

Теперь я хочу объединить их в один файл FOO_RES.csv, который будет иметь следующий формат:

FOOA,1,0,0,0,0,0,0...

FOOB,1,0,0,0,0,0,0...

FOOC,1,0,0,0,1,0,0...

FOOD,0,0,0,0,0,0,0...

...

Какой простой и элегантный способ провести это (с хэшами и массивами -> $ hash {$ key} = \ @data)?

Большое спасибо за любую помощь!

Йохад

Ответы [ 5 ]

3 голосов
/ 14 июля 2009

Если вы не можете четко описать свои данные и желаемый результат, вы не сможете закодировать их - простой проект - хороший способ начать использовать новый язык.

Позвольте мне представить простой метод, который вы можете использовать для производства кода на любом языке, знаете ли вы это или нет. Этот метод работает только для небольших проектов. Вам нужно будет заранее планировать крупные проекты.

Как написать программу:

  1. Откройте ваш текстовый редактор и запишите, какие данные у вас есть. Сделать каждую строку комментарием
  2. Опишите желаемые результаты.
  3. Начните описывать шаги, необходимые для преобразования ваших данных в желаемую форму.

Заполнены номера 1 и 2:

#!/usr/bin perl
use strict;
use warnings;

# Read data from multiple files and combine it into one file.
# Source files:
#    Field definitions: has a list of field names, one per line.
#    Data files:  
#      * Each data file has a string of digits.
#      * There is a one-to-one relationship between the digits in the data file and the fields in the field defs file.
# 
# Results File:
# * The results file is a CSV file.
# * Each field will have one row in the CSV file.
# * The first column will contain the name of the field represented by the row.
# * Subsequent values in the row will be derived from the data files.
# * The order of subsequent fields will be based on the order files are read.
# * However, each column (2-X) must represent the data from one data file.

Теперь, когда вы знаете, что у вас есть, и куда вам нужно идти, вы можете выяснить, что нужно сделать программе, чтобы попасть туда - это шаг 3:

Вы знаете, что вам нужен список полей, поэтому сначала получите его:

# Get a list of fields.
#   Read the field definitions file into an array.

Поскольку писать CSV проще всего ориентированным на строки способом, вам нужно будет обработать все ваши файлы перед созданием каждой строки. Поэтому вам понадобится место для хранения данных.

# Create a variable to store the data structure.

Теперь мы читаем файлы данных:

# Get a list of data files to parse
# Iterate over list

# For each data file:
#    Read the string of digits.
#    Assign each digit to its field.
#    Store data for later use.

У нас есть все данные в памяти, теперь запишите вывод:

# Write the CSV file.
# Open a file handle.

# Iterate over list of fields
# For each field
#   Get field name and list of values.
#   Create a string - comma separated string with field name and values  
#   Write string to file handle

# close file handle.

Теперь вы можете начать преобразовывать комментарии в код. Вы можете иметь от 1 до 100 строк кода для каждого комментария. Вы можете обнаружить, что что-то, что вам нужно сделать, очень сложно, и вы не хотите это делать в данный момент. Создайте фиктивную подпрограмму для выполнения сложной задачи и игнорируйте ее, пока все остальное не будет сделано. Теперь вы можете решить эту сложную, непростую подзадачу самостоятельно.

Так как вы только изучаете Perl, вам нужно нажать на документацию, чтобы узнать, как выполнить каждую из подзадач, представленных в комментариях, которые вы написали. Лучший ресурс для этого вида работы - список функций по категориям в perlfunc . Руководство по синтаксису Perl также пригодится. Поскольку вам нужно работать со сложной структурой данных, вам также нужно прочитать из Data Structures Cookbook .

Вам может быть интересно, как, черт возьми, вы должны знать, какие perldoc-страницы вам следует читать для данной проблемы. Статья о Perlmonks под названием Как сделать RTFM представляет собой хорошее введение в документацию и как ее использовать.

Самое замечательное, если вы застряли, у вас есть код, которым вы можете поделиться, когда обращаетесь за помощью.

1 голос
/ 13 июля 2009

Похоже, у вас есть много файлов foo_files с 1 строкой, что-то вроде:

1110000000

Что означает

fooa=1
foob=1
fooc=1
food=0
fooe=0
foof=0
foog=0
fooh=0
fooi=0
fooj=0

И, похоже, ваш foo_res является просто суммой этих значений? В этом случае вам нужен не хеш массивов, а просто хеш.

my @foo_files = (); #NOT SURE HOW YOU POPULATE THIS ONE
my @foo_keys = qw(a b c d e f g h i j);
my %foo_hash = map{ ( $_, 0 ) } @foo_keys; # initialize hash
foreach my $foo_file ( @foo_files ) {
  open( my $FOO, "<", $foo_file) || die "Cannot open $foo_file\n";
  my $line = <$FOO>;
  close( $FOO );
  chomp($line);
  my @foo_values = split(//, $line);
  foreach my $indx ( 0 .. $#foo_keys ) {
    last if ( ! $foo_values[ $indx ] ); # or some kind of error checking if the input file doesn't have all the values
    $foo_hash{ $foo_keys[$indx] } += $foo_values[ $indx ];
  }
}

Довольно сложно понять, о чем вы просите, но, может быть, это поможет?

1 голос
/ 13 июля 2009

Ваши характеристики не ясны. Вы не можете иметь «множество других файлов» с именем FOO_files.txt, потому что это только одно имя. Поэтому я собираюсь принять это как шаблон «файлы с данными + список файлов». В этом случае существуют файлы с именем FOO*.txt, каждый из которых содержит «[01] + \ n».

Таким образом, идея состоит в том, чтобы обработать все файлы в файле списка файлов и вставить их все в файл результатов FOO_RES.csv, разделенный запятыми.

use strict;
use warnings;
use English qw<$OS_ERROR>;
use IO::Handle;

open my $foos, '<', 'FOO_1.txt'
    or die "I'm dead: $OS_ERROR";
@ARGV = sort map { chomp; "$_.txt" } <$foos>;
$foos->close;

open my $foo_csv, '>', 'FOO_RES.csv'
    or die "I'm dead: $OS_ERROR";

while ( my $line = <> ) { 
    my ( $foo_name ) = ( $ARGV =~ /(.*)\.txt$/ );
    $foo_csv->print( join( ',', $foo_name, split //, $line ), "\n" );
}

$foo_csv->close;
1 голос
/ 13 июля 2009

Если я правильно понимаю, ваш первый файл - это файл порядка ключей, а остальные файлы содержат байты на ключ в том же порядке. Вам нужен составной файл этих ключей, в котором каждый из их байтов данных будет указан вместе.

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

0 голосов
/ 13 июля 2009

Вам не нужно использовать хеш. Мой Perl немного ржавый, поэтому синтаксис может быть немного , но в основном это делается:

open KEYFILE , "foo_1.txt" or die "cannot open foo_1 for writing";
open VALFILE , "foo_files.txt" or die "cannot open foo_files for writing";
open OUTFILE , ">foo_out.txt"or die "cannot open foo_out for writing";

my %output;
while (<KEYFILE>) {
    my $key = $_;
    my $val = <VALFILE>;
    my $arrVal = split(//,$val);

    $output{$key} = $arrVal;
    print OUTFILE $key."," . join(",", $arrVal)
}

Редактировать: Синтаксическая проверка ОК

Комментарий Синан: @Byron, меня действительно беспокоит, что ваше первое предложение говорит, что OP не нуждается в хэше, но ваш код имеет %output, который, кажется, не имеет смысла. Для справки ниже приведен менее подробный способ сделать то же самое.

#!/usr/bin/perl

use strict;
use warnings;

use autodie qw(:file :io);

open my $KEYFILE, '<', "foo_1.txt";
open my $VALFILE, '<', "foo_files.txt";
open my $OUTFILE, '>', "foo_out.txt";

while (my $key = <$KEYFILE>) {
    chomp $key;
    print $OUTFILE join(q{,}, $key, split //, <$VALFILE> ), "\n";
}
__END__
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...