Java中的二维数组

17

这对我来说是一个麻烦的问题...我是一名PHP程序员,在JSP项目中工作。我知道如何通过编写冗长的代码和完全缺乏技巧来实现我所尝试的内容。

我更希望能够做得更好。以下是情况:

我正在编写一个小型显示屏,以根据客户的浇水组(ABCDE)和年份的时间来显示客户可以在哪些日期浇水。我们的季节如下: 夏季(5-1至8-31) 春季(3-1至4-30) 秋季(9-1至10-31) 冬季(11-1至2-28)

例如:

如果我在A组,我的允许时间如下: 冬季:仅限周一 春季:周二,周四,周六 夏季:任意日 秋季:周二,周四,周六

如果我在PHP中编写此代码,我将使用以下数组:

//M=Monday,t=Tuesday,T=Thursday.... etc
$schedule["A"]["Winter"]='M';
$schedule["A"]["Spring"]='tTS';
$schedule["A"]["Summer"]='Any';
$schedule["A"]["Fall"]='tTS';
$schedule["B"]["Winter"]='t';

我可以把日期设为数组(array("星期二","星期四","星期六")),但实际上并不需要这么做。

我还需要设置数组来确定当前季节:

$seasons["Summer"]["start"]=0501;
$seasons["Summer"]["end"]=0801;

有人能提供一个非常酷的方法来完成这个吗?我将拥有今天的日期和小组字母。我需要从我的函数中获取一天(M)或一系列天(tTS),(任何)。

12个回答

0

简短概述

使用现代Java语言特性和类,定义自己的枚举来表示季节和组。

Schedule.daysForGroupOnDate( 
    Group.D , 
    LocalDate.now()
)  

该方法返回一个Set对象,其中包含DayOfWeek枚举对象(而不仅仅是文本!),例如DayOfWeek.TUESDAYDayOfWeek.THURSDAY

现代Java

有人能提供一种非常酷的方法来解决这个问题吗?

可以。

现代Java内置了类、集合和枚举,可帮助您解决此问题。

Java内置的java.time框架提供了Month枚举和DayOfWeek枚举。

EnumSetEnumMap提供了SetMap的实现,这些实现针对枚举类型进行了优化,以在非常少的内存中快速执行。

您可以定义自己的枚举类型来表示季节和组(A、B等)。Java中的枚举工具比其他语言中看到的要更有用和强大。如果不熟悉,请参阅Oracle教程

定义自己的枚举类型的简单语法实际上提供了解决这个问题所需的大部分功能,消除了一些复杂的编码。Java 9中集合工厂方法中的collections factory methods新的literals syntax用于设置和映射(JEP 269)现在使代码更加简单。
这是一个完整的工作应用程序。请注意算法中有多少代码。定义自己的自定义枚举类型完成了大部分的重活。
这个应用程序代码的一个警告:它假设您的业务定义不会发生任何变化,或者至少如果有变化,您只关心当前规则,“最新的是最好的”。如果您的规则随时间改变,并且您需要表示所有过去、现在和未来版本,我将构建一个非常不同的应用程序,可能需要使用数据库来存储规则。但是,这个应用程序可以解决所提出的问题。

Season

将您的季节表示为枚举Season。每个季节对象都包含一个List,其中包含定义该特定季节长度的Month枚举对象。Java 9中添加的新List.of语法通过静态工厂方法以字面量语法定义不可变列表。

package com.basilbourque.watering;

import java.time.LocalDate;
import java.time.Month;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

public enum Season
{
    SPRING( List.of( Month.MARCH , Month.APRIL ) ),
    SUMMER( List.of( Month.MAY , Month.JUNE, Month.JULY , Month.AUGUST ) ),
    FALL( List.of( Month.SEPTEMBER , Month.OCTOBER ) ),
    WINTER( List.of( Month.NOVEMBER , Month.DECEMBER , Month.JANUARY , Month.FEBRUARY ) );

    private List< Month > months;

    // Constructor
    Season ( List < Month > monthsArg )
    {
        this.months = monthsArg;
    }

    public List < Month > getMonths ( )
    {
        return this.months;
    }

    // For any given month, determine the season.
    static public Season ofLocalMonth ( Month monthArg )
    {
        Season s = null;
        for ( Season season : EnumSet.allOf( Season.class ) )
        {
            if ( season.getMonths().contains( monthArg ) )
            {
                s = season;
                break; // Bail out of this FOR loop.
            }
        }
        return s;
    }

    // For any given date, determine the season.
    static public Season ofLocalDate ( LocalDate localDateArg )
    {
        Month month = localDateArg.getMonth();
        Season s = Season.ofLocalMonth( month );
        return s;
    }

    // Run `main` for demo/testing.
    public static void main ( String[] args )
    {
        // Dump all these enum objects to console.
        for ( Season season : EnumSet.allOf( Season.class ) )
        {
            System.out.println( "Season: " + season.toString() + " = " + season.getMonths() );
        }
    }
}

分组

将每个客户草坪/庭院的分组(A、B、C、D、E)表示为名为Group的枚举。每个这些枚举对象都持有一个Map,将Season枚举对象映射到DayOfWeek枚举对象的Set。例如,在Season.SPRING中的Group.A允许在两天浇水,即DayOfWeek.TUESDAYDayOfWeek.THURSDAY

package com.basilbourque.watering;

import java.time.DayOfWeek;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;

public enum Group
{
    A(
            Map.of(
                    Season.SPRING , EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.THURSDAY ) ,
                    Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
                    Season.FALL , EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.THURSDAY ) ,
                    Season.WINTER , EnumSet.of( DayOfWeek.TUESDAY )
            )
    ),
    B(
            Map.of(
                    Season.SPRING , EnumSet.of( DayOfWeek.FRIDAY ) ,
                    Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
                    Season.FALL , EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.FRIDAY ) ,
                    Season.WINTER , EnumSet.of( DayOfWeek.FRIDAY )
            )
    ),
    C(
            Map.of(
                    Season.SPRING , EnumSet.of( DayOfWeek.MONDAY ) ,
                    Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
                    Season.FALL , EnumSet.of( DayOfWeek.MONDAY , DayOfWeek.TUESDAY ) ,
                    Season.WINTER , EnumSet.of( DayOfWeek.MONDAY )
            )
    ),
    D(
            Map.of(
                    Season.SPRING , EnumSet.of( DayOfWeek.WEDNESDAY , DayOfWeek.FRIDAY ) ,
                    Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
                    Season.FALL , EnumSet.of( DayOfWeek.FRIDAY ) ,
                    Season.WINTER , EnumSet.of( DayOfWeek.WEDNESDAY )
            )
    ),
    E(
            Map.of(
                    Season.SPRING , EnumSet.of( DayOfWeek.TUESDAY ) ,
                    Season.SUMMER , EnumSet.allOf( DayOfWeek.class ) ,
                    Season.FALL , EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.WEDNESDAY ) ,
                    Season.WINTER , EnumSet.of( DayOfWeek.WEDNESDAY )
            )
    );

    private Map < Season, Set < DayOfWeek > > map;

    // Constructor
    Group ( Map < Season, Set < DayOfWeek > > mapArg )
    {
        this.map = mapArg;
    }

    // Getter
    private Map < Season, Set < DayOfWeek > > getMapOfSeasonToDaysOfWeek() {
        return this.map ;
    }

    // Retrieve the DayOfWeek set for this particular Group.
    public Set<DayOfWeek> daysForSeason (Season season ) {
        Set<DayOfWeek> days =   this.map.get( season ) ; // Retrieve the value (set of days) for this key (a season) for this particular grouping of lawns/yards.
        return days;
    }



    // Run `main` for demo/testing.
    public static void main ( String[] args )
    {
        // Dump all these enum objects to console.
        for ( Group group : EnumSet.allOf( Group.class ) )
        {
            System.out.println( "Group: " + group.toString() + " = " + group.getMapOfSeasonToDaysOfWeek() );
        }
    }

}

日程表

在这个日程表类中将所有内容整合起来。

该类利用上面定义的两个枚举类型来完成有用的工作。目前只实现了一个方法,它可以告诉您特定日期和特定组别允许哪些星期几进行浇水。该方法确定适用于该日期的季节

在此运行main方法以转储我们的两个枚举类型的内容,并报告每个组别在特定硬编码日期允许浇水的星期几。

package com.basilbourque.watering;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;
import java.util.EnumSet;
import java.util.Set;

public class Schedule
{
    static private DateTimeFormatter isoWeekFormatter = DateTimeFormatter.ofPattern( "uuuu-'W'ww" ) ;

    static public Set < DayOfWeek > daysForGroupOnDate ( Group group , LocalDate localDate )
    {
        Season season = Season.ofLocalDate( localDate );
        Set < DayOfWeek > days = group.daysForSeason( season );
        return days;
    }

    // Run `main` for demo/testing.
    public static void main ( String[] args )
    {
        Season.main( null  );
        Group.main( null  );
        // Dump all these enum objects to console.
        for ( Group group : EnumSet.allOf( Group.class ) )
        {
            LocalDate localDate = LocalDate.now( ZoneId.of( "Africa/Tunis" ) );
            Set < DayOfWeek > days = Schedule.daysForGroupOnDate( group , localDate );
            String week = localDate.format( Schedule.isoWeekFormatter  ) ; // Standard ISO 8601 week, where week number one has the first Thursday of the calendar year, and week starts on Monday, so year is either 52 or 53 weeks long.
            String message = "Group " + group + " – Watering days on " + localDate + " week # " + week + " is: " + days;
            System.out.println( message );
        }
    }
}

控制台

运行Schedule.main时,我们可以在控制台中看到以下输出。

季节:春天 = [三月,四月] 季节:夏天 = [五月,六月,七月,八月] 季节:秋天 = [九月,十月] 季节:冬天 = [十一月,十二月,一月,二月] 组:A = {春天=[星期二,星期四],秋天=[星期二,星期四],夏天=[星期一,星期二,星期三,星期四,星期五,星期六,星期日],冬天=[星期二]} 组:B = {春天=[星期五],秋天=[星期二,星期五],夏天=[星期一,星期二,星期三,星期四,星期五,星期六,星期日],冬天=[星期五]} 组:C = {春天=[星期一],秋天=[星期一,星期二],夏天=[星期一,星期二,星期三,星期四,星期五,星期六,星期日],冬天=[星期一]} 组:D = {春天=[星期三,星期五],秋天=[星期五],夏天=[星期一,星期二,星期三,星期四,星期五,星期六,星期日],冬天=[星期三]} 组:E = {春天=[星期二],秋天=[星期二,星期三],夏天=[星期一,星期二,星期三,星期四,星期五,星期六,星期日],冬天=[星期三]} A组 - 2018-01-30周的浇水日#2018-W05是:[星期二] B组 - 2018-01-30周的浇水日#2018-W05是:[星期五] C组 - 2018-01-30周的浇水日#2018-W05是:[星期一] D组 - 2018-01-30周的浇水日#2018-W05是:[星期三] E组 - 2018-01-30周的浇水日#2018-W05是:[星期三]

ISO 8601周

了解ISO 8601标准对于周的定义可能会有所帮助。该标准为“周”给出了特定的含义,并定义了表示特定周或特定周内某一天的文本格式。

如果在Java中处理这样的周,考虑将ThreeTen-Extra库添加到您的项目中,以利用YearWeek类。

LocalDate

LocalDate类表示仅带日期的值,不带时间和时区。

时区对于确定日期非常重要。对于任何给定的时刻,日期因时区而异。例如,在法国巴黎午夜过后几分钟是新的一天,而在加拿大魁北克省蒙特利尔仍然是“昨天”。

如果没有指定时区,则JVM隐式地应用其当前默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好将所需/预期的时区明确指定为参数。

请以大陆/地区的格式指定正确的时区名称,例如{{link2:America/Montreal}}、{{link3:Africa/Casablanca}}或Pacific/Auckland。不要使用3-4个字母的缩写,如ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的!

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

如果您想使用JVM的当前默认时区,请请求并将其作为参数传递。如果省略,则隐式应用JVM的当前默认值。最好明确指出。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

或者指定一个日期。您可以通过数字设置月份,1-12代表一月到十二月。

LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ;  // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.

或者更好的方法是使用预定义的Month枚举对象,每个月份一个。提示:在整个代码库中使用这些Month对象,而不是仅使用整数数字,可以使您的代码更加自我记录、确保有效值并提供类型安全
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;

不可变集合

上面提到的列表、集合和映射应该是不可变集合,因为更改这些集合的成员可能会导致混乱和错误。

新的Java 9语法List.ofMap.of已经承诺是不可变的。然而,在我们的情况下,Map应该是一个EnumMap,以提高性能和内存效率。目前Map.ofSet.of的实现似乎没有检测到枚举作为成员的使用,并自动优化使用内部的EnumMapEnumSet。有一个OpenJDK问题开放来考虑这些问题:考虑增强EnumMap和EnumSet

获取不可变的EnumSet和不可变的EnumMap的一种方法是通过Google Guava库:

每个结果都使用底层的EnumSet/EnumMap。像getput这样的操作会抛出异常。因此,您可以获得与枚举相关的优化以及不可变性。

这里是使用Google Guava 23.6库修改后的SeasonGroup类。

带有不可变性的Season

package com.basilbourque.watering;

import java.time.LocalDate;
import java.time.Month;
import java.util.EnumSet;
import java.util.List;

public enum Season
{
    SPRING( List.of( Month.MARCH , Month.APRIL ) ),  // `List.of` provides literals-style syntax, and returns an immutable `List`. New in Java 9.
    SUMMER( List.of( Month.MAY , Month.JUNE, Month.JULY , Month.AUGUST ) ),
    FALL( List.of( Month.SEPTEMBER , Month.OCTOBER ) ),
    WINTER( List.of( Month.NOVEMBER , Month.DECEMBER , Month.JANUARY , Month.FEBRUARY ) );

    private List< Month > months;

    // Constructor
    Season ( List < Month > monthsArg )
    {
        this.months = monthsArg;
    }

    public List < Month > getMonths ( )
    {
        return this.months;
    }

    // For any given month, determine the season.
    static public Season ofLocalMonth ( Month monthArg )
    {
        Season s = null;
        for ( Season season : EnumSet.allOf( Season.class ) )
        {
            if ( season.getMonths().contains( monthArg ) )
            {
                s = season;
                break; // Bail out of this FOR loop.
            }
        }
        return s;
    }

    // For any given date, determine the season.
    static public Season ofLocalDate ( LocalDate localDateArg )
    {
        Month month = localDateArg.getMonth();
        Season s = Season.ofLocalMonth( month );
        return s;
    }

    // Run `main` for demo/testing.
    public static void main ( String[] args )
    {
        // Dump all these enum objects to console.
        for ( Season season : EnumSet.allOf( Season.class ) )
        {
            System.out.println( "Season: " + season.toString() + " = " + season.getMonths() );
        }
    }
}

具有不可变性的

package com.basilbourque.watering;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import java.time.DayOfWeek;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;

public enum Group
{
    A(
            Maps.immutableEnumMap(
                    Map.of(  // `Map.of` provides literals-style syntax, and returns an immutable `Map`. New in Java 9.
                            Season.SPRING , Sets.immutableEnumSet( DayOfWeek.TUESDAY , DayOfWeek.THURSDAY ) ,
                            Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
                            Season.FALL , Sets.immutableEnumSet( DayOfWeek.TUESDAY , DayOfWeek.THURSDAY ) ,
                            Season.WINTER , Sets.immutableEnumSet( DayOfWeek.TUESDAY )
                    )
            )
    ),

    B(
            Maps.immutableEnumMap(
                    Map.of(
                            Season.SPRING , Sets.immutableEnumSet( DayOfWeek.FRIDAY ) ,
                            Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
                            Season.FALL , Sets.immutableEnumSet( DayOfWeek.TUESDAY , DayOfWeek.FRIDAY ) ,
                            Season.WINTER , Sets.immutableEnumSet( DayOfWeek.FRIDAY )
                    )
            )
    ),

    C(
            Maps.immutableEnumMap(
                    Map.of(
                            Season.SPRING , Sets.immutableEnumSet( DayOfWeek.MONDAY ) ,
                            Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
                            Season.FALL , Sets.immutableEnumSet( DayOfWeek.MONDAY , DayOfWeek.TUESDAY ) ,
                            Season.WINTER , Sets.immutableEnumSet( DayOfWeek.MONDAY )
                    )
            )
    ),

    D(
            Maps.immutableEnumMap(
                    Map.of(
                            Season.SPRING , Sets.immutableEnumSet( DayOfWeek.WEDNESDAY , DayOfWeek.FRIDAY ) ,
                            Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
                            Season.FALL , Sets.immutableEnumSet( DayOfWeek.FRIDAY ) ,
                            Season.WINTER , Sets.immutableEnumSet( DayOfWeek.WEDNESDAY )
                    )
            )
    ),

    E(
            Maps.immutableEnumMap(
                    Map.of(
                            Season.SPRING , Sets.immutableEnumSet( DayOfWeek.TUESDAY ) ,
                            Season.SUMMER , Sets.immutableEnumSet( EnumSet.allOf( DayOfWeek.class ) ) ,
                            Season.FALL , Sets.immutableEnumSet( EnumSet.of( DayOfWeek.TUESDAY , DayOfWeek.WEDNESDAY ) ) ,
                            Season.WINTER , Sets.immutableEnumSet( DayOfWeek.WEDNESDAY )
                    )
            )
    );

    private Map < Season, Set < DayOfWeek > > map;

    // Constructor
    Group ( Map < Season, Set < DayOfWeek > > mapArg )
    {
        this.map = mapArg;
    }

    // Getter
    private Map < Season, Set < DayOfWeek > > getMapOfSeasonToDaysOfWeek ( )
    {
        return this.map;
    }

    // Retrieve the DayOfWeek set for this particular Group.
    public Set < DayOfWeek > daysForSeason ( Season season )
    {
        Set < DayOfWeek > days = this.map.get( season ); // Retrieve the value (set of days) for this key (a season) for this particular grouping of lawns/yards.
        return days;
    }

    // Run `main` for demo/testing.
    public static void main ( String[] args )
    {
        // Dump all these enum objects to console.
        for ( Group group : EnumSet.allOf( Group.class ) )
        {
            System.out.println( "Group: " + group.toString() + " = " + group.getMapOfSeasonToDaysOfWeek() );
        }
    }

}

关于java.time

java.time框架内置于Java 8及以上版本中。这些类取代了老旧的遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

想要了解更多,请查看Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310

如何获取java.time类?

ThreeTen-Extra 项目通过添加额外的类扩展了 java.time。该项目是 java.time 可能未来增加内容的试验场。您可能会在这里找到一些有用的类,例如 Interval, YearWeek, YearQuarter更多


0

没有完美的解决方案。Java并不擅长处理这样的事情。如果你想要将字符串作为索引(键),那么Mike的解决方案基本上是正确的方法。如果哈希表嵌套设置太丑陋,另一个选择是将字符串连接在一起(从Mike那里无耻地窃取并进行修改):

Hashtable<String, String> schedule = new Hashtable<String, String>();
schedule.put("A-Winter", "M");
schedule.put("A-Spring", "tTS");

然后查找:

String val = schedule.get(group + "-" + season);

如果你对于总体的丑陋感到不满(我也不怪你),可以将所有内容封装在一个方法调用中:

String whenCanIWater(String group, Date date) { /* ugliness here */ }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接