【问题标题】:Convert hash into csv file将哈希转换为 csv 文件
【发布时间】:2011-05-30 06:26:07
【问题描述】:

我得到了一个哈希:

%hash = (
Honda.Blue => '10',
Honda.Red => '10',
Honda.Yellow => '60',
Ford.Blue => '20',
Ford.Red => '25',
Ford.Yellow => '26',
Toyota.Blue => '17',
Toyota.Red => '16',
Toyota.Yellow => '18',
);

需要将此哈希转换为具有以下标题(make,blue_volume,red_volume,yellow_volume)的csv文件并用数据填充它

#Make,blue_volume,red_volume,yellow_volume
#Honda,10,10,60
#Ford,20,25,26
#Toyota,17,16,18


loop over %hash
     @array = split('.',$key);
     $make=$array[0];
    $line = "$make,$hash{'$make.Blue'},$hash{'$make.Red'},$hash{'$make.Yellow'}";
     push(@lines,$line);


foreach (@lines)
{
    open (LOG, '>>summary.csv');
    print LOG "$_";
    close (LOG);
}

需要帮助找出这段代码。

【问题讨论】:

    标签: arrays perl csv hash


    【解决方案1】:

    第一步:

    • use strict; 说:
      • Bareword "Honda" not allowed while "strict subs" in use at xx.pl line 4.

    这不是一种经过批准的创建哈希的方式。我建议:

    use strict;
    use warnings;
    
    my %hash = (
    Honda  => { Blue => '10', Red => '10', Yellow => '60' },
    Ford   => { Blue => '20', Red => '25', Yellow => '26' },
    Toyota => { Blue => '17', Red => '16', Yellow => '18' },
    );
    

    那么,您可能应该使用Text::CSV。然而,通过简单的操作来输出并不是那么难。我们可以利用您要求的蓝色、红色、黄色恰好按字母顺序排列的事实:

    print "make,blue_volume, red_volume,yellow_volume\n";
    foreach my $make (sort keys %hash)
    {
        print "$make";
        foreach my $colour (sort keys %{$hash{$make}})
        {
            print ",$hash{$make}{$colour}";
        }
        print "\n";
    }
    

    对于样本哈希,输出为:

    make,blue_volume, red_volume,yellow_volume
    Ford,20,25,26
    Honda,10,10,60
    Toyota,17,16,18
    

    如果存在需要使用引号或其他任何内容的风险,我会使用 Text::CSV。

    【讨论】:

      【解决方案2】:

      List::MoreUtils 的解决方案。

      #!/usr/bin/env perl
      use warnings;
      use 5.012;
      use List::MoreUtils qw/first_index/;
      use Text::CSV;
      
      my $file_out = 'my_new_file.csv';
      
      my %hash = (
      'Honda.Blue' => '10',
      'Honda.Red' => '10',
      'Honda.Yellow' => '60',
      'Ford.Blue' => '20',
      'Ford.Red' => '25',
      'Ford.Yellow' => '26',
      'Toyota.Blue' => '17',
      'Toyota.Red' => '16',
      'Toyota.Yellow' => '18',
      );
      
      my @brands = qw( Honda Ford Toyota );
      my @colors = qw( Blue Red Yellow );
      my @array;
      for my $key ( keys %hash ) {
          my( $brand, $color ) = split /\./, $key, 2;
          my $idx_1 = first_index { $_ eq $brand } @brands;   
          my $idx_2 = first_index { $_ eq $color } @colors;
          $array[$idx_1][0] = $brand;
          $array[$idx_1][$idx_2+1] = $hash{$key};
      }
      
      my $csv = Text::CSV->new ( { binary => 1, eol => $/, auto_diag => 2 } ) 
      or die Text::CSV->error_diag();
      my $col_names = [ qw( Make blue_volume red_volume yellow_volume ) ];
      open my $fh, '>:encoding(UTF-8)', $file_out or die $!;
      $csv->print ( $fh, $col_names );
      $csv->print ( $fh, $_ ) for @array;
      close $fh;
      

      【讨论】:

        【解决方案3】:

        如果您遍历哈希并为每个键创建一行,则每个 make 将重复 3 次;相反,通过循环 %hash、提取 make 并设置 $makes{$make} = 1 来创建另一个包含所有 make 的哈希。然后循环生成您的行。

        当您从 %hash 键中提取 make 时,使用 /\./ 作为拆分模式; split 总是使用一个模式,而不是一个简单的字符串(有一个奇怪的例外),并且您不想在每个字符上进行拆分,这就是 split '.'会做(感谢 codaddict 指出这部分)。

        '$make.Blue' 使用单引号,因此不会插入变量。请改用"$make.Blue"

        将 open 和 close 分别移动到 @lines 循环之前和之后。没有理由为每一行打开文件。

        不要忘记每行末尾的“\n”(除非您使用 -l 标志或 say 而不是 print)。

        【讨论】:

          【解决方案4】:

          查看Text::CSV::Slurp。它将允许您将哈希转换为 CSV,反之亦然。

          【讨论】:

          • 在这种情况下,需要对哈希进行处理以获取数据以进入 CSV 文件; Text::CSV::Slurp 不会为你做这些。
          • @ysth - 但这并不意味着它仍然不是一个可行的选择。
          【解决方案5】:

          对于那些有兴趣的我能够弄清楚,感谢大家的帮助!

          my %hash; 
          $hash{'aaa.biz'} = 'domainRegistered'; 
          $hash{'aaa.com'} = 'domainRegistered'; 
          $hash{'aaa.info'} = 'domainRegistered'; 
          $hash{'aaa.net'} = 'domainRegistered'; 
          $hash{'aaa.org'} = 'domainRegistered'; 
          
          $hash{'bbb.biz'} = 'domainRegistered'; 
          $hash{'bbb.com'} = 'domainRegistered'; 
          $hash{'bbb.info'} = 'domainRegistered'; 
          $hash{'bbb.org'} = 'domainRegistered'; 
          $hash{'bbb.us'} = 'domainRegistered'; 
          
          foreach $key (sort keys %hash) 
          {   
              @array=split("\\.",$key);
              push (@names, $array[0]); 
          }
          
          #Extract unique values and sort
          my %seen = ();
          my @result = grep { !$seen{$_}++ } @names; 
          @names = sort { $a <=> $b } @result;
          
          foreach $element (@names)
          {
              foreach $key (sort keys %hash) 
              {   
                  @array=split("\\.",$key);
                  if (@array [0] eq $element){push (@values, $hash{$key});}
              }
              $values = join(",",@values);
              $line = "$element,$values";
              undef @values;
              push(@lines,$line);
          }
          print join("\n",@lines);
          open (summary, '>>summary.csv');
          print summary join("\n",@lines);
          close (summary); 
          

          【讨论】:

          • 很好奇;这与这个问题几乎没有共同之处。答案中没有出现本田、福特、丰田的名字;域名未出现在问题中。
          猜你喜欢
          • 2012-12-21
          • 1970-01-01
          • 1970-01-01
          • 2019-08-01
          • 1970-01-01
          • 2010-11-04
          • 2019-10-27
          • 2019-05-23
          • 1970-01-01
          相关资源
          最近更新 更多