资讯专栏INFORMATION COLUMN

用二进制字符串作为索引,构建时间段

2json / 1980人阅读

摘要:于是,我写了下面的函数检查格式,必须是位仅含的字符串找出对应的位置,通过,最终余留的元素就是已选中的几个值,非选中元素被剔除了如果所有的时段都没有被订利用剩下的这个进行字符串处理用两个遍历,解决了这个问题。

最近跟二进制字符串杠上了,总是喜欢对二进制字符串存储和运算进行研究。今天又来写一个使用场景的代码。

使用场景:在项目中需要存储一个对象被租用的时间段,以每个小时作为一个时间段,从8:00到晚上20:00,一共12个时间段;现在按照二进制字符串的形式存储每个时间段被租用的情况,如果该时段被租用,就在对应的位置上用1表示,未租用就用0表示,例如 001100000100 表示10:00-12:00,17:00-18:00这两个时间段被租用,并将该二进制字符串存储在数据库中;现在,在读取数据时,需要将二进制字符串还原为时间段,(如果出现连续的时间段时,需合并为一个跨多个小时的时间段),写一个函数来实现。

在面对这个问题的时候,我想了很多,因为我们要从便捷性和效率两个角度去思考,如果仅仅是为了实现便捷性,那么通过拆分数组,遍历,一定能很快实现。于是,我写了下面的函数:

function bin_string_to_hours($string,$hours = array("08:00-09:00","09:00-10:00","10:00-11:00","11:00-12:00","12:00-13:00","13:00-14:00","14:00-15:00","15:00-16:00","16:00-17:00","17:00-18:00","18:00-19:00","19:00-20:00"))
{
    // 检查$string格式,必须是12位仅含01的字符串
    if(!preg_match("/^[0|1]{12}$/",$string)) return false;
    // 找出对应的位置,通过unset,最终余留的$hours元素就是已选中的几个值,非选中元素被剔除了
    $arr = str_split($string);
    foreach($arr as $key => $value) {
        if($value == 0) unset($hours[$key]);
    }
    // 如果所有的时段都没有被订
    if(empty($hours)) return null;
    // 利用剩下的这个$hours进行字符串处理
    $hours = array_values($hours);
    $result = array();
    list($start, $last) = explode("-", $hours[0]);
    for($i = 1, $n = count($hours); $i < $n; $i++) {
        list($start2, $last2) = explode("-", $hours[$i]);
        if ($start2 != $last) {
            $result[] = $start . "-" . $last;
            $start = $start2;
            $last = $last2;
        } else {
            $last = $last2;
        }
    }
    $result[] = $start . "-" . $last;
    unset($hours);
    return implode(",", $result);
}

用两个遍历,解决了这个问题。但是,有没有更烧脑的解决办法呢?我又做了下面的修改。

function bin_string_to_hours($string,$hours = array("08:00-09:00","09:00-10:00","10:00-11:00","11:00-12:00","12:00-13:00","13:00-14:00","14:00-15:00","15:00-16:00","16:00-17:00","17:00-18:00","18:00-19:00","19:00-20:00"))
{
    // 检查$string格式,必须是12位仅含01的字符串
    if(!preg_match("/^[0|1]{12}$/",$string)) return false;
    // 通过对字符串进行数组切割,然后通过循环遍历,找出所有1,并将连续的(或单个的)1分为一个组
    $i = 0;
    $groups = array();
    $arr = str_split($string);
    foreach($arr as $key => $value) {
        if(isset($arr[$key - 1]) && $arr[$key - 1] == $value) // 如果上一个元素与当前元素相等(同为1或0),不进行任何操作
        {}
        else // 如果当前元素与上一个元素不同(一个为0,一个为1),那么新建一个组
        {
            $i ++;
        }
        if($value == 0) // 如果该值为0,这个组别就没有存在的必要了
        {
            unset($groups[$i]);
            continue;
        }
        $groups[$i][] = $key; // 把对应的索引存入到组中
    }
    // 从分组中取出对应的索引,在按每组去对字符串进行处理:该组的第一个索引对应的字串的前面部分,和最后一个索引对应的字串的后面部分,就是时间的开始与截止
    $return = array();
    foreach($groups as $group) {
        $index_start = current($group);
        if(count($group) == 1) // 如果这个组只有一个元素,也就是只有一个时间段,直接返回这个时间段的值即可
        {
            $return[] = $hours[$index_start];
            continue;
        }
        $index_end = end($group);
        $string_start = current(explode("-",$hours[$index_start]));
        $string_end = end(explode("-",$hours[$index_end]));
        $return[] = $string_start."-".$string_end;
    }
    $return = implode("-",$return);
    return $return;
}

通过分组构建分组数组的方法来解决,如果数据量大的时候,明显这种方法更加节省资源。可是,当我和小伙伴儿再继续烧脑的时候,在马上把脑袋烤熟的一瞬间,我们发现了只需要一次遍历就可以解决问题的办法。

function bin_string_to_hours($string,$hours = array("08:00","09:00","10:00","11:00","12:00","13:00","14:00","15:00","16:00","17:00","18:00","19:00","20:00"))
{
    if(!preg_match("/^[0|1]{12}$/",$string)) return false; // 检查$string格式,必须是12位仅含01的字符串

    $result = array();
    $index_start = 0; // 用来记录连续的1最前的索引
    $index_end = 0; // 用来记录连续的1最末的索引
    $count = 0; // 用来记录有多少个连续的1
    for($i = 0; $i <= 12; $i ++)
    {
        if($i < 12 && $string[$i] == "1") // string最大索引为11,所以这里必须<12
        {
            if($count == 0) $index_start = $i;
            $index_end = $i + 1;
            $count ++;
        }
        else
        {
            if($count > 0 && $index_end - $index_start == $count) // count必须>0的情况下,在能进行字符串组合,为0就没有意义了
                $result[] = $hours[$index_start]."~".$hours[$index_end];
            $count = 0;
        }
    }

    return implode(",",$result);
}

这个算法里面,把上面原本用时间段作为元素的$hours,改成了把每个小时时间点作为元素,很快,一个循环就把我们的目标效果实现了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21088.html

相关文章

  • Redis深入系列-0x014:Redis数据类型和概念介绍(上)

    摘要:比特数组使用特殊的命令可以向处理比特数组一样处理字符串,你可以设置或者清除独立的比特,将所有的比特设置为,找到第一个比特等等等不解释。的的是比特安全的,这意味着你可以使用任何的二进制序列作为,从像的字符串到一个文件的内容。 0x000 概述 Redis不是一个简单键值对存储器,而是一个数据结构服务,它支持不同类型的值。这意味着传统的键值对存储器将字符串键和字符串值关联起来,在Redis...

    Miracle 评论0 收藏0
  • JavaScript 编程精解 中文第三版 四、数据结构:对象和数组

    摘要:本章将介绍基本的数据结构。松鼠人一般在晚上八点到十点之间,雅克就会变身成为一只毛茸茸的松鼠,尾巴上的毛十分浓密。我们将雅克的日记表示为对象数组。 来源:ApacheCN『JavaScript 编程精解 中文第三版』翻译项目原文:Data Structures: Objects and Arrays 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了《Jav...

    kamushin233 评论0 收藏0
  • Lucene 构建文档数据库

    摘要:说到档案系统,选文档数据库再合适不过了。熟悉的人看这个会很眼熟,没错,这就是从借鉴过来,并用在我的关系数据库查询上。接口规范接口的主要目是为了传递数据,数据结构已经在上面给出。为便于不同系统不同终端的数据交换,也将应当在接口支持之内。 说到档案系统,选文档数据库再合适不过了。谈到文档数据库一般想到的是 MongoDB、CouchDB 之类的,可这里要说的不是这些,而是另一个 NoSQL...

    Paul_King 评论0 收藏0
  • Lucene 构建文档数据库

    摘要:说到档案系统,选文档数据库再合适不过了。熟悉的人看这个会很眼熟,没错,这就是从借鉴过来,并用在我的关系数据库查询上。接口规范接口的主要目是为了传递数据,数据结构已经在上面给出。为便于不同系统不同终端的数据交换,也将应当在接口支持之内。 说到档案系统,选文档数据库再合适不过了。谈到文档数据库一般想到的是 MongoDB、CouchDB 之类的,可这里要说的不是这些,而是另一个 NoSQL...

    inapt 评论0 收藏0
  • Lucene 构建文档数据库

    摘要:说到档案系统,选文档数据库再合适不过了。熟悉的人看这个会很眼熟,没错,这就是从借鉴过来,并用在我的关系数据库查询上。接口规范接口的主要目是为了传递数据,数据结构已经在上面给出。为便于不同系统不同终端的数据交换,也将应当在接口支持之内。 说到档案系统,选文档数据库再合适不过了。谈到文档数据库一般想到的是 MongoDB、CouchDB 之类的,可这里要说的不是这些,而是另一个 NoSQL...

    zhangyucha0 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<