Вы находитесь на правильном пути с хэшем, вам просто нужно вычислить ключ по столбцам для каждой таблицы. Раздел решения:
$key
@order
, т.е. он определяет порядок вывода таблицы %table
под ключом $key
: поместите столбцы, идущие из этой таблицы в финальную таблицу, в массив ref @order
$key
из хэша %table
#!/usr/bin/perl
use warnings;
use strict;
use autodie;
use Text::CSV;
my $csv = Text::CSV->new({
binary => 1,
eol => "\n",
sep_char => "\t",
}) or die "CSV creation\n";
sub read_file($) {
my($file, $code) = @_;
open(my $fh, '<', $file);
while (my $row = $csv->getline( $fh )) {
$code->($row);
}
$csv->eof or $csv->error_diag();
close($fh);
}
# Output table + row order
my %table;
my @order;
# Table 1
read_file($ARGV[0], sub {
my($row) = @_;
#print "ROW 1 @{ $row }\n";
my($col1, $col2) = @{ $row }[1,2];
# column_1, column_2 define key
my $key = "${col1}${col2}";
#print "KEY 1 ${key}\n";
# table 1 defines order
push(@order, $key);
# ID, column_1, column_2, column_3 from table 1
$table{$key} = $row;
});
# Table 2
read_file($ARGV[1], sub {
my($row) = @_;
#print "ROW 2 @{ $row }\n";
my($col4, $col5, $col6) = @{ $row };
# column_4, column_5 define key
my $key = "${col4}${col5}";
#print "KEY 2 ${key}\n";
# column_6 from table 2
push(@{ $table{$key} }, $col6);
});
# Table 3
read_file($ARGV[2], sub {
my($row) = @_;
#print "ROW 3 @{ $row }\n";
my($col7, $col8, $col9, $col10) = @{ $row };
# column_7, column_10 define key
my $key = "${col7}${col10}";
#print "KEY 3 ${key}\n";
# column_7, column_8 from table 2
push(@{ $table{$key} }, $col7, $col8);
});
foreach my $key (@order) {
$csv->print(\*STDOUT, $table{$key});
}
exit 0;
Тестовый прогон:
$ perl dummy.pl dummy1.txt dummy2.txt dummy3.txt
A 100 100001 X X 100 120000
B 100 99999 Y Y 100 66666
C 100 88888 Z Z 100 77777
D 99 100001 Y Y 99 100000
E 99 88888 Z Z 99 44444
Для Java 6 или выше это идеальный случай для FileNameExtensionFilter
... за исключением того, что он расширяет javax.swing.filechooser.FileFilter
вместо реализации java.io.FileFilter
.
Но написать обёртку для него - тривиальная задача:
File[] files = rootDir.listFiles(new FileFilter() {
private final FileNameExtensionFilter filter =
new FileNameExtensionFilter("Compressed files",
"zip", "jar", "z", "gz", "tar", "bz2", "bz");
public boolean accept(File file) {
return filter.accept(file);
}
});
Почему бы не использовать регулярные выражения?
static final Pattern p = Pattern.compile ("\\. (Zip | jar | z | gz) $");
а затем return p.matcher (name) .find ();
Некоторые решения псевдокода:
suffixes = [".tar", ".zip", ".jpg"]
for suffix in suffixes:
if name.endsWith(suffix):
return True
suffixes = [".tar", ".zip", ".jpg"]
nameSuffix = name.getSuffix()
if nameSuffix in suffixes:
return True
Я только что закончил писать этот класс:
class FileExtensionFilter implements FileFilter {
private final String[] validExtensions;
public FileExtensionFilter(String... validExtensions) {
this.validExtensions = validExtensions;
}
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
return true;
}
String name = pathname.getName().toLowerCase();
for (String ext : validExtensions) {
if (name.endsWith(ext)) {
return true;
}
}
return false;
}
}
использование:
File files[] = directory.listFiles(
new FileExtensionFilter(".zip", ".jar", ".z", ".tar"));
Кстати, это многоразовый class, вы даже можете обернуть его дополнительными проверками, используя шаблон декоратора и т. д.
PS
только что заметил существование FileNameExtensionFilter
Вы можете сделать следующее, используя статически инициализированный HashSet. Лично я бы вытащил разрешенные расширения в какой-то файл конфигурации, чтобы его было немного легче изменить, но вам это не обязательно.
nb FilenameUtils принадлежит Commons I / O , который также включает в себя набор классов, которые упрощают выполнение подобных действий. Взгляните также на FileFilterUtils , который еще больше упрощает работу и предоставляет несколько полезных вспомогательных методов.
private static Set allowedExtensions = null;
static {
allowedExtensions = new HashSet<String>();
allowedExtensions.add("txt");
allowedExtensions.add("zip");
allowedExtensions.add("jar");
allowedExtensions.add("gz");
}
public void filter() {
File rootDir = new File("/");
File files[] = rootDir.listFiles(new FileFilter() {
public boolean accept(File file) {
if (file.isDirectory()) return true;
String fileName = file.getName().toLowerCase();
String extension = FilenameUtils.getExtension(fileName);
if (StringUtils.isNotEmpty(extension)
&& allowedExtensions.contains(extension)) {
return true;
} else {
return false;
}
}
});
}
Вы можете найти API здесь:
Вы можете статически создать карту и вернуть истину, если расширение имени файла является ключом в карте.
Или вы можете попытаться сопоставить имя файла с регулярным выражением (но я бы предпочел использовать карту вместо этого).
Вот мой подход. java.lang.Collections - действительно хороший класс! И поскольку мы ищем данное расширение файла в HashSet, оно более производительно. Хотя сомневаюсь, что в данном случае производительность действительно имеет значение ...
// ...
final Set<String> archives = new HashSet<String>();
Collections.addAll(archives, ".zip", ".jar", ".z", ".gz", ".tar",
".bz2", ".bz");
File files[] = rootDir.listFiles(new FileFilter() {
public boolean accept(final File file) {
if (file.isDirectory())
return true;
final String name = file.getName().toLowerCase();
return archives.contains(name
.substring(name.lastIndexOf('.')));
}
});
// ...