如何确定数组中的值是否位于两个附加数组的所有并行索引的值之间

How can I determine if value from array lies between values at all parallel indices of two additional arrays?

本文关键字:数组 并行 索引 之间 何确定 是否 于两个      更新时间:2023-09-26

我有四个数组,具有以下角色:

  1. 所有现有开始日期(未选中)
  2. 所有现有结束日期(未选中)
  3. 所选项目的开始日期(选中)
  4. 所选项目结束日期(选中)

1 和 2 包含集合中所有未选定事件的开始和结束时间戳池。

选中与

事件关联的复选框时,将使用开始和结束时间戳填充 3 和 4,取消选中这些复选框时,将删除时间戳。

结果应该是,如果未选定项目的日期范围

与新选定项目的日期范围冲突,请阻止它们被选中,并直观地显示它们是禁用的选项。

我目前让它将所有未选中的项目的值与比较数组中最近检查的日期进行比较,但它忽略了之前的日期。这意味着我可能会选择一个冲突的日期被禁用,但是当我选择另一个可用选项时,以前禁用的选项会重新启用。

我不是 100% 确定如何确保将所有未选中的项目与所有选中的项目进行比较,并根据日期是否冲突而禁用。 在现有循环中添加嵌套的 for 循环是解决此问题的最佳方法吗?

附言我知道有一些奇怪的选择器和额外的工作来格式化日期,但我这样做的人坚持日期格式为周一## - ##(同月)和周一## - 周一##(不同的月份)和日期包含在复选框标签中的小标签中。

    var camp_dates;
    var camp_start;
    var camp_end;
    var other_camp_dates;
    var other_camp_start;
    var other_camp_end;
    var checked_start = [];
    var checked_end = [];
    var year = new Date().getFullYear();
    // Change checkbox apply filters
    $("#gform_11 input[type=checkbox]").click(function(){
        //Reset list of checked items
        checked_start = [];
        checked_end = [];
        camp_dates = $("label[for='" + $(this).attr("id") + "'] small").html().split("-");
        camp_start = camp_dates[0].split(" ");
        camp_end = camp_dates[1].split(" ");
        //If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
        if (camp_end.length == 1){
            camp_end.unshift(camp_start[0]);
        }
        //rejoin day and months, add year to parse for timestamp
        camp_start = Date.parse(camp_start.join(" ") + ", " + year);
        camp_end = Date.parse(camp_end.join(" ") + ", " + year);
        //Take empty start and arrays and add dates for selections
        $(".gfield_checkbox input:checked").each(function(){
            //All currently checked items
            checked_start.push(camp_start);
            checked_end.push(camp_end);
        });
        $(".gfield_checkbox input:not(:checked) + label small").each(function(){
            //Gen values for all unselected items
            other_camp_dates = $(this).html().split("-");
            other_camp_start = other_camp_dates[0].split(" ");
            other_camp_end = other_camp_dates[1].split(" ");
            //If no month in end date, assume same month as first
            if (other_camp_end.length == 1){
                other_camp_end.unshift(other_camp_start[0]);
            }
            //rejoin day and months, add year to parse for timestamp
            other_camp_start = Date.parse(other_camp_start.join(" ") + ", " + year);
            other_camp_end = Date.parse(other_camp_end.join(" ") + ", " + year);
            // Loop through arrays of start/end dates and compare to each unselected item - apply fade, disable, color
            var i;
            for (i = 0; i < checked_start.length; i++) {
                if ( other_camp_start >= checked_start[i] && other_camp_start < checked_end[i] ||
                    other_camp_end > checked_start[i] && other_camp_end <= checked_end[i] ){
                    // If there is conflict
                    $(this).css("color", "red").parent().fadeTo("slow",0.5).siblings("input").not(":checked").attr("disabled", true);
                } else {
                    $(this).css("color", "#7E7E7E").parent().fadeTo("slow",1).siblings("input").attr("disabled", false);
                }
            }
        });
    });

http://codepen.io/wjramos/pen/BywyRY

如果我理解正确,这比代码所暗示的要简单。

首先,可以通过编写一个parseDates()函数来消除用于解析日期的重复代码,该函数:

  • 返回具有 .start.end 属性的对象。
  • 可以用作.map()回调,一次用于选中,一次用于未选中的复选框。

然后,剩下的工作是根据嵌套循环中的所有选中日期检查所有未选中的日期,并管理未选中的项目的禁用状态。执行此操作的一个主要因素是仅在所有禁用项目已知时重新启用项目 - 即在两个嵌套循环完成后。

代码应该是这样的:

// Change checkbox apply filters
$("#gform_11 input[type=checkbox]").click(function(){
    var year = new Date().getFullYear();
    //A utility function for parsing out start and end dates
    function parseDates() {
        var dates = $(this).html().split("-"),
            start = dates[0].split(" "),
            end = dates[1].split(" ");
        //If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
        if (end.length == 1) {
            end.unshift(start[0]);
        }
        //return an object with .start and .end properties
        return {
            start: Date.parse(start.join(" ") + ", " + year), //rejoin 
            end: Date.parse(end.join(" ") + ", " + year) //rejoin 
        };
    }
    //A utility function for comparing a checked date with an unchecked date
    function compareDateRanges(checked, unchecked) {
        return ( unchecked.start >= checked.start && unchecked.start < checked.end ) ||
            ( unchecked.end > checked.start && unchecked.end <= checked.end )
    }
    var $checked = $(".gfield_checkbox input:checked");
    var $unchecked = $(".gfield_checkbox input:not(:checked)").removeClass('disabled');
    var checkedDates = $checked.siblings("label").find("small").map(parseDates).get();//make array of start-end objects for checked inputs
    var uncheckedDates = $unchecked.siblings("label").find("small").map(parseDates).get();//make array of start-end objects for unchecked inputs
    for(var i=0; i<checkedDates.length; i++) {
        for(var j=0; j<uncheckedDates.length; j++) {
            if(compareDateRanges(checkedDates[i], uncheckedDates[j])) {
                // If there is conflict
                $unchecked.eq(j).addClass('disabled').attr('disabled', true).siblings("label").find("small").css('color', 'red').parent().fadeTo('slow', 0.5);
            }
        }
    }
    //when all disabled elements are known, all others can be eneabled.
    $unchecked.not(".disabled").attr('disabled', false).siblings("label").find("small").css('color', '#7E7E7E').parent().fadeTo('slow', 1);
});

演示

编辑 1

为了满足可能跨越新年的日期范围:

//A utility function for parsing out start and end dates
function parseDates() {
    var dates = $(this).siblings("label").find("small").html().split("-"),
        start = dates[0].split(" "),
        end = dates[1].split(" ");
    //If no month in end date, assume same month as first (Ex. Jul 06-22 == Jul 06 - Jul 22)
    if (end.length == 1) {
        end.unshift(start[0]);
    }
    var obj = {
        start: Date.parse(start.join(" ") + ", " + year), //rejoin 
        end: Date.parse(end.join(" ") + ", " + year) //rejoin 
    }
    // Test for the date range spanning a New Year.
    // If necessary, reparse `end` with next year's date
    if(obj.end < obj.start) {
        obj.end = Date.parse(end.join(" ") + ", " + (year + 1));
    }
    //return an object with .start and .end properties
    return obj;
}

编辑 2

要在页面加载时执行,请触发第一个复选框的单击处理程序:

$("#gform_11 input[type=checkbox]").click(function() {
    ... ...
}).eq(0).triggerHandler('click');

是否选中第一个复选框并不重要,因为无论元素的 :checked 状态如何,所有内容都是通过计算的。

您似乎在启用/禁用复选框的方式上遇到问题。您正在循环浏览每个未选择的项目,如果它们与选定的项目冲突,则禁用它们,如果没有,则启用它们。

这就是为什么这是一个问题:假设您有一个未选中的日期与选中的日期冲突。禁用未选中的。

但是在循环的稍后,当您与另一个检查它并且没有冲突时,您会重新启用它。如果沿循环的某个位置禁用,则应保持禁用状态。

另一个问题是:当你有你的评论"//Take empty start and arrays and add dates for selections"时,你一遍又一遍地推送相同的值(camp_startcamp_end),而没有得到每个选定的日期。

以下是修订版:

jQuery(document).ready(function($){
    var camp_dates,
        other_camp_dates,
        checked_dates = [],
        year = new Date().getFullYear();
    // Change checkbox apply filters
    $("#gform_11 input[type=checkbox]").click(function(){
        //Reset list of checked items
        checked_dates = [];
        camp_dates = formatDates( $("label[for='" + $(this).attr("id") + "'] small").html() );
        //Take empty checked_dates and add dates for selections
        $(".gfield_checkbox input:checked + label small").each(function(){
            //All currently checked items
            checked_dates.push( formatDates( $(this).html() ) );
        });
        // For each unchecked item
        $(".gfield_checkbox input:not(:checked) + label small").each(function(){
            //Get the dates
            other_camp_dates = formatDates( $(this).html() );
            // Enable the checkbox before matching it with all checked_dates
            // If we don't do that now, imagine we have a date that conflicts (we disable it),
            // and the next one does not conflict : we reenable it. Not what we want.
            $(this).css("color", "#7E7E7E").parent().css("opacity",1).siblings("input").attr("disabled", false);
            // Loop through arrays of checked_dates and compare to the current unchecked item
            var i, l = checked_dates.length;
            for (i = 0; i<l; i++) {
                if ( other_camp_dates.start >= checked_dates[i].start && other_camp_dates.start < checked_dates[i].end ||
                    other_camp_dates.end > checked_dates[i].start && other_camp_dates.end <= checked_dates[i].end ){
                    //Conflict
                    $(this).css("color", "red").parent().css("opacity",.5).siblings("input").not(":checked").attr("disabled", true);
                }
                // If there is no conflict for this one, there may be one for a previous one,
                // so we don't enable it here
            }
        });
    });
    // It's messy enough to make it a function and not rewrite it
    function formatDates(str){
        var dates = str.split("-"),
            start_date = dates[0].split(" "),
            end_date = dates[1].split(" ");
        if (end_date.length == 1){
            end_date.unshift(start_date[0]);
        }
        start_date = Date.parse(start_date.join(" ") + ", " + year);
        end_date = Date.parse(end_date.join(" ") + ", " + year);
        return {
            "start" : start_date,
            "end"   : end_date
        };
    }
}); // jQuery(document).ready

JS小提琴演示