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个回答

11
你可以使用哈希表(或其他映射)实现基本相同的代码:
Hashtable<String, Hashtable<String, String>> schedule
    = new Hashtable<String, Hashtable<String, String>>();
schedule.put("A", new Hashtable<String, String>());
schedule.put("B", new Hashtable<String, String>());
schedule.put("C", new Hashtable<String, String>());
schedule.put("D", new Hashtable<String, String>());
schedule.put("E", new Hashtable<String, String>());

schedule.get("A").put("Winter", "M");
schedule.get("A").put("Spring", "tTS");
// Etc...

虽然不太优雅,但毕竟Java并非动态语言,因此它在语言层面上没有哈希表。

注意:您可能能够提供更好的解决方案,我读到您的问题时突然想到的就是这个。


4
为了获得更好的性能,应该使用HashMap而不是Hashtable。Hashtable和Vector一样,非常老旧,因此出于性能原因不应使用。主要原因是它将所有内容都同步处理,尽管这并不必要。 - MetroidFan2002

9
不要试图像PHP一样动态。你可以先尝试定义需要的内容。
interface Season
{
    public string getDays();
}

interface User
{
    public Season getWinter();
    public Season getSpring();
    public Season getSummer();
    public Season getFall();
}

interface UserMap
{
    public User getUser(string name);
}

请在使用Hashtable之前阅读Hashtable文档。这个类是同步的,这意味着每个调用都受到多线程保护,这会在你不需要额外保护时减慢访问速度。请使用任何Map实现,如HashMapTreeMap

+1 我认为接口名称 User 应该重命名为 UserGroup 以增加清晰度。 - zawhtut

6

似乎每个人都在试图找到用Java实现PHP的方法,而不是按照Java应有的方式来完成。可以将数组的每个部分视为一个对象,或者至少将数组的第一层视为一个对象,将每个子层视为对象内的变量。然后构建一个数据结构,用这些对象填充它,并通过数据结构的访问器访问这些对象。

类似于以下内容:

class Schedule
{
  private String group;
  private String season;
  private String rundays;
  public Schedule() { this.group = null; this.season = null; this.rundays= null; }
  public void setGroup(String g) { this.group = g; }
  public String getGroup() { return this.group; }
  ...
}

public ArrayList<Schedule> schedules = new ArrayList<Schedule>();
Schedule s = new Schedule();
s.setGroup(...);
...
schedules.add(s);
...

当然,这也可能不是正确的方法。我会将每个季节作为一个对象,并且也许每个工作日列表也作为一个对象。无论如何,这比一个拼凑在一起的哈希表更易于重用、理解和扩展,后者试图模仿你的PHP代码。当然,PHP也有对象,你应该尽可能地像使用超级数组一样使用它们,而不是使用哈希表。我确实理解作弊的诱惑。PHP使它变得如此简单,如此有趣!


4
这是一种可能的演示方式,你可以自行推断其余部分:
A = new Group();
A.getSeason(Seasons.WINTER).addDay(Days.MONDAY);
A.getSeason(Seasons.SPRING).addDay(Days.TUESDAY).addDay(Days.THURSDAY);
A.getSeason(Seasons.SPRING).addDays(Days.MONDAY, Days.TUESDAY, ...);

schedule = new Schedule();
schedule.addWateringGroup( A );

3

我不是Java程序员,但是从语言无关的角度来思考,更干净的方法可能是使用常量或枚举类型。这应该适用于支持多维数组的任何语言。

如果使用命名常量,例如:

int A = 0;
int B = 1;
int C = 2;
int D = 3;

int Spring = 0; 
int Summer = 1;
int Winter = 2; 
int Fall = 3;
...

常量可以作为更易读的数组下标:

schedule[A][Winter]="M";
schedule[A][Spring]="tTS";
schedule[A][Summer]="Any";
schedule[A][Fall]="tTS";
schedule[B][Winter]="t";

使用枚举类型:

enum groups
{
  A = 0,
  B = 1,
  C = 2,
  D = 3
}

enum seasons
{
  Spring = 0,
  Summer = 1,
  Fall = 2,
  Winter = 3
}
...
schedule[groups.A][seasons.Winter]="M";
schedule[groups.A][seasons.Spring]="tTS";
schedule[groups.A][seasons.Summer]="Any";
schedule[groups.A][seasons.Fall]="tTS";
schedule[groups.B][seasons.Winter]="t";

2

我赞同将函数封装在对象中的做法。

import java.util.Date;
import java.util.Map;
import java.util.Set;

public class Group {

    private String groupName;

    private Map<Season, Set<Day>> schedule;

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Map<Season, Set<Day>> getSchedule() {
        return schedule;
    }

    public void setSchedule(Map<Season, Set<Day>> schedule) {
        this.schedule = schedule;
    }

    public String getScheduleFor(Date date) {
        Season now = Season.getSeason(date);
        Set<Day> days = schedule.get(now);
        return Day.getDaysForDisplay(days);
    }

}

编辑:另外,您的日期范围没有考虑闰年:

我们的季节如下:夏季(5月1日至8月31日)、春季(3月1日至4月30日)、秋季(9月1日至10月31日)和冬季(11月1日至2月28日)。


2

我完全不明白为什么你们中的一些人似乎认为向代码中抛出大量对象是正确的方法。例如,季节只有四个,并且它们不会执行或存储任何内容。将其转换成对象如何简化问题?Wing 是对的,这些应该是常量(或者可能是枚举)。

Bruce 需要的是一个查找表。他不需要对象和接口的层次结构;他需要一种根据季节和组标识查找日程的方法。只有当对象具有职责或状态时,将其转换成对象才有意义。如果它们既没有职责也没有状态,则它们只是标识符,为它们构建特殊对象只会使代码库变得更大。

你可以创建 Group 对象,每个对象包含一组日程字符串(每个季节一个),但是如果所有 Group 对象都只提供查找功能,那么你就重新发明了查找表,而且方式不太直观。如果他必须查找组,然后查找日程,那么他只有一个需要两步查找的查找表,编码时间更长,更容易出错,维护起来也更困难。


1

我同意你应该把这个逻辑放在干净的界面后面:

public String lookupDays(String group, String date);

但也许你应该将数据存储在属性文件中。我不反对在源文件中硬编码这些数据,但正如你所注意到的,当涉及到嵌套集合时,Java可能会变得非常冗长。你的文件可能看起来像:

A.Summer=M
A.Spring=tTS
B.Summer=T

通常我不喜欢将这样的静态数据移动到外部文件中,因为它增加了数据和使用它的代码之间的“距离”。然而,每当你处理嵌套集合,特别是映射时,事情就会变得非常丑陋,非常快。

如果你不喜欢这个想法,也许你可以做一些类似这样的事情:

public class WaterScheduler
{
  private static final Map<String, String> GROUP2SEASON = new HashMap<String, String>();
  static
  {
    addEntry("A", "Summer", "M");
    addEntry("A", "Spring", "tTS");
    addEntry("B", "Summer", "T");
  }

  private static void addEntry(String group, String season, String value)
  {
    GROUP2SEASON.put(group + "." + season, value);
  }

}

你会失去一些可读性,但至少数据会更接近它将要使用的地方。


1

“date”是否必须作为参数?如果您只是展示当前的浇水计划,WateringSchedule类本身可以找出今天是哪一天,从而知道现在是什么季节。然后只需编写一个方法,返回一个映射表,其中键是组字母。例如:

public Map<String,List<String>> getGroupToScheduledDaysMap() {
  // instantiate a date or whatever to decide what Map to return
}

然后在 JSP 页面中

<c:forEach var="day" items="${scheduler.groupToScheduledDaysMap["A"]}">
   ${day}
</c:forEach>

如果您需要显示多个季节的时间表,您应该在WateringSchedule类中有一个方法,该方法返回一个映射,其中季节是键,groupToScheduledDays是值的映射。

1

一个更好的解决方案也许是将所有这些数据放入数据库中,而不是在源代码中硬编码或使用属性文件。

使用数据库将更容易维护,而且有多种免费的数据库引擎可以选择。

其中两个数据库引擎完全采用Java实现,可以通过包含jar文件嵌入到应用程序中。当然它有一点重量级,但它更可扩展和易于维护。今天只有20条记录并不意味着由于需求变化或功能扩展以后不会有更多的记录。

如果几周或几个月后您决定要添加比如说每天特定时间浇水的限制,如果您已经在使用数据库,则添加该功能将更加容易。即使从未发生过这种情况,那么您只需要花费几个小时学习如何在应用程序中嵌入数据库。


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