如何使用Perl按升序对日期进行排序?

时间:2016-11-29 03:40:05

标签: perl

以下是我的代码:

import java.util.Stack;

public class SO_40856348 
{
    public static void main(String[] args) 
    {
        Stack<String> stack = new Stack<>();

        // add 10 events to the stack (0-9)
        for(int x = 0; x<10; x++)
        {
            String event = "Event-"+x;
            System.out.println("At iteration [" + x + "] before adding event [" + event + "] stack contains:");
            printStack(stack);

            addEvent(stack, event);

            System.out.println("At iteration [" + x + "] after adding event [" + event + "] stack contains:");
            printStack(stack);
        }

        // dump events to console
        System.out.println("At the end of the program the stack contains:");
        printStack(stack);
    }

    public static void printStack(Stack<String> stack)
    {
        for(String e : stack)
        {
            System.out.println(e);
        }
    }

    public static void addEvent(Stack<String> stack, String event)
    {
        /* Never more than 5 events in the stack, if we current have 5, 
         * remove one and immediately add the next one.
         */
        if(stack.size() == 5)
        {
            // remove the oldest entry from the bottom of the stack
            stack.remove(0);
        }
        // push the newest entry onto the top of the stack
        stack.push(event);
    }
}

预期输出应为按升序排列的日期。

5 个答案:

答案 0 :(得分:4)

你要去的地方:

sub sortByDate{
    my ($am, $ad, $ay) = $a =~ /(\d{2})\/(\d{2})\/(\d{4})/;    
    my ($bm, $bd, $by) = $b =~ /(\d{2})\/(\d{2})\/(\d{4})/;   
    $ay <=> $ay || $am <=> $bm || $ad <=> $bd
}

如果您要将日期重新排列为yyyymmdd格式,则只需使用词典排序。

我相信这是最快的解决方案:

my @sorted_events =
    map { substr($_, 8) }
    sort
    map { sprintf('%3$04d%1$02d%2$02d%4$s', split(qr{/}, $_), $_) }
    @events;

答案 1 :(得分:2)

首先转换为Time::Piece,然后sort的工作方式与您预期的完全一样。

#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;

my @events=('11/17/1999',  '12/6/1999', '12/23/1999',  
         '1/23/2000',  '1/13/2000',  '2/25/2000', 
           '1/5/2000',  '3/18/2000',  '4/10/2000', 
          '3/12/2000', '12/31/1999');

foreach my $event ( @events ) {
   $event = eval { Time::Piece->strptime($event, "%m/%d/%Y" )} || $event;
}

print join "\n", sort { $a <=> $b }  @events;
print "\n";
print join "\n", map { $_ -> strftime("%Y-%m-%d") } sort { $a <=> $b } @events;

注意 - 在上面,如果strptime失败,它将保留原始字符串。这会在sort中引发警告,因为您不再按数字排序。

答案 2 :(得分:0)

尝试以下简单的排序功能。
警告:不进行任何数据格式检查

//Background.java
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;

public class Background extends JPanel implements Runnable {
        private BufferedImage image;
        private int topEdgeY;

        public Background(){
                try {
                        image = ImageIO.read(new File("background.png"));
                }
                catch (Exception e){}
                topEdgeY = 0;
        }

        public void run(){
                repaint();
        }

        public void paintComponent(Graphics g){
              super.paintComponent(g);
              g.drawImage(image, 0, topEdgeY, getWidth(), getHeight(), this);    
              g.drawImage(image, 0, topEdgeY - getWidth(), getWidth(), getHeight(), this);
        }
        public void move(){
              topEdgeY += 5;
              if (topEdgeY == getWidth())
                  topEdgeY = 0;
              repaint();
       }
}

答案 3 :(得分:0)

您是否查看了可用的日期处理模块?我相信有些人会为你完成大部分的工作......

无论如何,上面代码的答案是:你的排序子有很多问题;代码甚至不在Perl 5.20上运行:

  1. 斜杠不会被转义,但它们是模式分隔符。我使用了m## - 在OP中也修复了转义。
  2. 您没有重新订购日期组件。重点是先把年份缩短;你觉得你在哪里做的?我sprintf()将日期修改为固定的YYYYMMDD号码。
  3. 您只是在$adate$bdate中分配匹配中的第一个元素,即仅按月排序 - 使用sprintf()
  4. 修复
  5. 您在日期组件中匹配固定字符串,但示例中的日/月有一个或两个字符。我改为使用\d{1,2}
  6. 这是一个固定的子:

    sub sortByDate {
        $a =~ m#(\d{1,2})/(\d{1,2})/(\d{4})#;
        my $adate = sprintf('%i%02i%02i', $3, $1, $2);
        $b =~ m#(\d{1,2})/(\d{1,2})/(\d{4})#;
        my $bdate = sprintf('%i%02i%02i', $3, $1, $2);
        return $adate <=> $bdate;
    }
    

    仍然没有错误检查,因此如果传递无效数据,使用strict / warning运行将返回大量错误。如果首先验证格式,则不需要额外的代码,但是为了防止错误形成日期的错误,您还可以添加一些检查并使用字符串cmp fallback:

    sub sortByDate {
        my $adate = sprintf('%i%02i%02i', $3, $1, $2)
            if ($a =~ m#(\d{1,2})/(\d{1,2})/(\d{4})#);
        my $bdate = sprintf('%i%02i%02i', $3, $1, $2)
            if ($b =~ m#(\d{1,2})/(\d{1,2})/(\d{4})#);
        return $adate <=> $bdate if ($adate && $bdate);
        return $a cmp $b;
    }
    

答案 4 :(得分:-1)

使用Perl可能有多种sort日期的方法。我在脚本中总结了两种方法。

这两种方法都使用Schwartzian transform对其进行排序。

  1. 只需使用拆分,然后根据年,月和日对其进行排序。如果您确定输入格式,请使用它。
  2. 使用Time::Piece解析Time::Piece个对象,然后对其进行排序。如果您不确定输入格式并在处理之前需要验证,请使用它。
  3. 您可以根据自己的喜好在他们之间使用任何人。

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Time::Piece;
    
    my @events = ( '11/17/1999',  '12/6/1999', '12/23/1999',
                   '1/23/2000',  '1/13/2000',  '2/25/2000',
                   '1/5/2000',  '3/18/2000',  '4/10/2000',
                   '3/12/2000', '12/31/1999');
    
    
    my @sorted_events = map { $_ -> [0] }
                        sort {
                              # year
                              $a -> [1] -> [2] <=> $b -> [1] -> [2] ||
                              # month
                              $a -> [1] -> [0] <=> $b -> [1] -> [0] ||
                              # day
                              $a -> [1] -> [1] <=> $b -> [1] -> [1]
                              }
                        map { [ $_, [ split /\// ] ] }
                        @events;
    
    # you can also use Time::Piece
    my @sorted_events_again = map { $_ -> [1] }
                              sort { $a -> [0] <=> $b -> [0] } 
                              map { [ Time::Piece -> strptime($_, "%m/%d/%Y"), $_ ] } 
                              @events;