【问题标题】:Store shop opening times店铺营业时间
【发布时间】:2014-05-31 04:58:57
【问题描述】:

这更像是一个应用设计问题,如果不相关,请见谅。

我正在开发的应用程序旨在显示该地区正在营业的商店,我不确定存储这些信息的最佳方式是什么。我从一个数据库(我没有设计)中获取信息,该数据库提供了一个布尔值数组,用于确定商店在此期间是否营业。每个布尔值代表一个 15 分钟的时隙,例如07:00-07:15.

这分为几天,但没有具体的日期,例如商店可以在周一至周五 09:00-17:00 但周六 09:00-20:00 营业,所以我保留的模型必须知道什么日期是但不一定是日期。

我不确定如何存储所有这些以方便/加快查找速度,因为我希望视图能够实时更新(商店从营业变为关闭而无需刷新)。我已经考虑向数据库中添加一个包含任何商店的营业时间(使用适当的时间和日期)的表,然后让 SQLite 完成所有艰苦的工作,让 Java 假设商店已关闭,除非它得到记录但感觉有点笨拙,因为以某种方式将开放时间保存在内存中可能会更好。

你能提供的任何帮助都会很棒。

【问题讨论】:

    标签: java android


    【解决方案1】:

    我将忽略数据库方面,因为您声称要从数组中获取一个布尔原始值数组。

    枚举、枚举集、枚举映射

    在 Java 方面,您可以使用 Java 中功能强大的 enum 以及 EnumSet。

    为所有时隙定义一个枚举。为简洁起见,我将只包括一些。我为每个枚举项添加了一个displayName 来获得更漂亮的标签。

    enum QuarterHour {
        T_0700_0715, T_0715_0730, T_0730_0745, T_0745_0800;
    
        public String displayName;
        public LocalTime start, stop;
    
        private QuarterHour () {
            // Soft-code the members of each enum item by parsing its name.
            this.displayName = this.name ().replace ( "T_" , "" ).replace ( "_" , "-" );
            String[] tokens = this.displayName.split ( "-" ); // Extract the start and stop times from the left and right parts of this string.
            String t1 = tokens[ 0 ].substring ( 0 , 2 ) + ":" + tokens[ 0 ].substring ( 2 );
            String t2 = tokens[ 1 ].substring ( 0 , 2 ) + ":" + tokens[ 1 ].substring ( 2 );
            this.start = LocalTime.parse ( t1 );
            this.stop = LocalTime.parse ( t2 );
            System.out.println ( "Debug construction of each QuarterHour enum item: " + this.name () + " with displayName: " + this.displayName + " from " + this.start + " to " + this.stop );
        }
    
    }
    

    Java 提供了非常快速和非常小的 EnumSet 和 EnumMap 类来收集 Enum 实例。每个分别是Set 和Map 的实现,就像任何其他实现一样。特殊之处在于,由于它们专用于Enum 实例,因此可以通过在内部使用bitmaps 对其进行高度优化。所以他们使用非常很少的内存并且执行速度非常快。

    暂时忽略您的布尔数组,这里有一些示例代码展示了如何使用EnumSet 和EnumMap。

    DayOfWeek

    我们的地图使用内置的 DayOfWeek 枚举,代表每周 7 天(周一至周日)中的每一天。

    java.time

    DayOfWeek 枚举是 Java 8 及更高版本中内置的 java.time 框架的一部分。这些类取代了旧的麻烦的日期时间类,例如java.util.Date。见Oracle Tutorial。大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 和 7,并在 ThreeTenABP 中进一步适应 Android。

    示例代码

    在此示例中,我有工作日从 07:00 到 08:00(四个刻钟)全时开放,周末从 07:30 到 08:00(两个刻钟)半小时后开放。

    EnumMap<DayOfWeek , EnumSet<QuarterHour>> days = new EnumMap<> ( DayOfWeek.class );
    EnumSet quarterHoursWhenOpen = EnumSet.of ( QuarterHour.T_0700_0715 , QuarterHour.T_0715_0730 , QuarterHour.T_0730_0745 , QuarterHour.T_0745_0800 );
    EnumSet quarterHoursWhenOpen2 = EnumSet.of ( QuarterHour.T_0730_0745 , QuarterHour.T_0745_0800 );
    
    days.put ( DayOfWeek.MONDAY , quarterHoursWhenOpen );
    days.put ( DayOfWeek.TUESDAY , quarterHoursWhenOpen );
    days.put ( DayOfWeek.WEDNESDAY , quarterHoursWhenOpen );
    days.put ( DayOfWeek.THURSDAY , quarterHoursWhenOpen );
    days.put ( DayOfWeek.FRIDAY , quarterHoursWhenOpen );
    days.put ( DayOfWeek.SATURDAY , quarterHoursWhenOpen2 );
    days.put ( DayOfWeek.SUNDAY , quarterHoursWhenOpen2 );
    

    转储到控制台。默认情况下,在我们的 QuarterHours 枚举上隐式调用的 toString 方法默认使用元素的名称。为了向您的用户展示,您可以调用我定义的displayName 方法,而不是调用内置的toString。 toString 方法被定义为用于“程序员友好”的字符串值,而不是面向用户的表示字符串。

    System.out.println ( "days: " + days );
    

    天:{MONDAY = [T_0700_0715,T_0715_0730,T_0730_0745,T_0745_0800],周二= [T_0700_0715,T_0715_0730,T_0730_0745,T_0745_0800],周三= [T_0700_0715,T_0715_0730,T_0730_0745,T_0745_0800],星期四= [T_0700_0715,T_0715_0730,T_0730_0745 , T_0745_0800], FRIDAY=[T_0700_0715, T_0715_0730, T_0730_0745, T_0745_0800], SATURDAY=[T_0730_0745, T_0745_0800], SUNDAY=[T_0730_0745]0}p>008

    顺便说一下,这种起止时间的命名遵循了处理时间跨度的常用方法,称为“半开放”,其中开始是包含而结束是独占。

    转化

    我们剩下要做的就是在 EnumSet QuarterHours 和布尔数组之间来回转换。有关更多信息,请参阅我的问题:Convert between EnumSet and array of boolean values。在这里,我使用了简单的 for 循环方法,但请查看 Java 8 及更高版本中更紧凑的 Lambda 和流语法的其他答案。

    以下代码在枚举上调用values 方法。令人讨厌的是,Enum 类中没有记录此方法,因为该方法是由编译器综合创建的,用于解决 this Question 中讨论的棘手内部技术问题。结果是该方法返回枚举中所有项目的数组。

    警告:所有这些代码都未经测试,只运行一次。使用风险自负。

    从 EnumSet 到数组

    // From EnumSet to array of boolean primitives.
    QuarterHour[] quarterHoursOfDay = QuarterHour.values ();
    boolean[] quarterHoursIfOpen = new boolean[ quarterHoursOfDay.length ];
    EnumSet<QuarterHour> enumSet = days.get ( DayOfWeek.SATURDAY );
    for ( int i = 0 ; i < quarterHoursOfDay.length ; i ++ ) {
        quarterHoursIfOpen[ i ] = enumSet.contains ( quarterHoursOfDay[ i ] );
    }
    

    转储到控制台。

    System.out.println ( "For " + DayOfWeek.SATURDAY + " array quarterHoursIfOpen: " + Arrays.toString ( quarterHoursIfOpen ) );
    

    对于 SATURDAY 数组 QuarterHoursIfOpen:[false, false, true, true]

    从数组到 EnumSet

    换个方向,从上面的布尔数组quarterHoursIfOpen 到下面名为enumSet2 的新EnumSet。

    // From array of boolean to EnumSet.
    EnumSet<QuarterHour> enumSet2 = EnumSet.noneOf ( QuarterHour.class );
    QuarterHour[] quarterHoursOfDay2 = QuarterHour.values ();
    for ( int i = 0 ; i < quarterHoursOfDay2.length ; i ++ ) {
        boolean isOpen = quarterHoursIfOpen[ i ];
        if ( isOpen ) {
            enumSet2.add ( quarterHoursOfDay[ i ] );
        }
    }
    

    转储到控制台。

    System.out.println ( "enumSet2: " + enumSet2 );
    

    枚举集2:[T_0730_0745,T_0745_0800]

    生成源代码

    这里是一些源代码,用于生成源代码以命名所有 24 小时值的四分之一小时枚举名称。

    StringBuilder enums = new StringBuilder ();
    LocalTime start = LocalTime.MIN;
    for ( int i = 0 ; i < ( 24 * 4 ) ; i ++ ) {
        if ( enums.length () > 0 ) {
            enums.append ( " , " );
        }
        LocalTime stop = start.plusMinutes ( 15 );
        String name = "T_" + start.toString () + "_" + stop.toString ();
        name = name.replaceAll ( ":" , "" );
        enums.append ( name );
        // Setup next loop
        start = stop;
    }
    System.out.println ( "enums: " + enums );
    

    枚举:T_0000_0015,T_0015_0030,T_0030_0045,T_0045_0100,T_0100_0115,T_0115_0130,T_0130_0145,T_0145_0200,T_0200_0215,T_0215_0230,T_0230_0245,T_0245_0300,T_0300_0315,T_0315_0330,T_0330_0345,T_0345_0400,T_0400_0415,T_0415_0430,T_0430_0445,T_0445_0500,T_0500_0515,T_0515_0530,T_0530_0545 ,T_0545_0600,T_0600_0615,T_0615_0630,T_0630_0645,T_0645_0700,T_0700_0715,T_0715_0730,T_0730_0745,T_0745_0800,T_0800_0815,T_0815_0830,T_0830_0845,T_0845_0900,T_0900_0915,T_0915_0930,T_0930_0945,T_0945_1000,T_1000_1015,T_1015_1030,T_1030_1045,T_1045_1100,T_1100_1115,T_1115_1130,T_1130_1145,T_1145_1200 ,T_1200_1215,T_1215_1230,T_1230_1245,T_1245_1300,T_1300_1315,T_1315_1330,T_1330_1345,T_1345_1400,T_1400_1415,T_1415_1430,T_1430_1445,T_1445_1500,T_1500_1515,T_1515_1530,T_1530_1545,T_1545_1600,T_1600_1615,T_1615_1630,T_1630_1645,T_1645_1700,T_1700_1715,T_1715_1730,T_1730_174 5,T_1745_1800,T_1800_1815,T_1815_1830,T_1830_1845,T_1845_1900,T_1900_1915,T_1915_1930,T_1930_1945,T_1945_2000,T_2000_2015,T_2015_2030,T_2030_2045,T_2045_2100,T_2100_2115,T_2115_2130,T_2130_2145,T_2145_2200,T_2200_2215,T_2215_2230,T_2230_2245,T_2245_2300,T_2300_2315,T_2315_2330,T_2330_2345, T_2345_0000

    【讨论】:

      【解决方案2】:

      我假设您的数据库如下所示:

      ("Bob's Bakery", [0,0,1,1,1,1, ... ])
      ("Aunt McGee's Gun-O-Rama", [0,0,0,0,1,1, ... ])
      ....
      

      在上面的示例中,我定义位数组从上午 07:00 开始。 “...”表示我懒得继续到下午 12:00 :)

      您可以使用该数据填充哈希映射,因此您最终会得到“start-of-15-min-slot”到“open shop”的映射。像这样的东西(简单的伪代码来可视化我的想法):

      openShops = {
         ("07:30",{"Bob's Bakery"}),
         ("07:45",{"Bob's Bakery"}),      
         ("08:00",{"Bob's Bakery","Aunt McGee's Gun-O-Rama"}),
         ("08:15",{"Bob's Bakery","Aunt McGee's Gun-O-Rama"}),
         ...
      }
      

      这样,您只需计算当前 15 分钟时隙的开始时间并执行一次查找。假设您想在 08:02 开店,那么您只需将分钟除以 15(没有余数)并将结果用作查询中分钟的值:

      2 格 15 = 0 → 08:00 → openShops.get("08:00") → ("Bob's Bakery","Aunt McGee's Gun-O-Rama")

      【讨论】:

      • 谢谢,我也在想类似的事情,理论上字符串“Bob's Bakery”甚至可以是商店对象。我目前的计划是将营业时间存储在 shop 对象中,然后从那里构建您所说的 hashmap。我认为这是其中之一,根据我想要访问数据的方式,有不止一种方法可以做到这一点。
      猜你喜欢
      • 1970-01-01
      • 2010-10-20
      • 2011-11-09
      • 1970-01-01
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多