Javascript 主干集合:迭代&;有效搜索

Javascript 主干集合:迭代&;有效搜索,javascript,backbone.js,Javascript,Backbone.js,我所拥有的:我正在编写我非常琐碎的媒体播放器。所以在它的某个地方我收集了一些字幕(比如说每部电影大约有2000个)。所以每个字幕看起来像: Object { id: "1" startTime: 2468 endTime: 4743 text: "Test subtitle." } 我想要:非常有效地做两件事: .next()方法,该方法将为我获取下一个副标题 .getByTime(neededTime)以有效的方式对整个字幕集进行类似于二进制搜索的搜索。关键是neededTi

我所拥有的:我正在编写我非常琐碎的媒体播放器。所以在它的某个地方我收集了一些字幕(比如说每部电影大约有2000个)。所以每个字幕看起来像:

Object {
  id: "1"
  startTime: 2468
  endTime: 4743
  text: "Test subtitle."
}
我想要:非常有效地做两件事:

  • .next()
    方法,该方法将为我获取下一个副标题
  • .getByTime(neededTime)
    以有效的方式对整个字幕集进行类似于二进制搜索的搜索。关键是
    neededTime
    可能介于
    startTime
    endTime
    属性之间(即3000)

  • 问题:我将在字幕中使用主干集,但它将如何处理这两个要求?我的意思是,也许手动实现迭代器模式和二进制搜索更好?

    不知道这是否是最佳解决方案,但我以以下内容结束:

    if (!Number.isInteger) {
        Number.isInteger = function isInteger (nVal) {
            return typeof nVal === "number" && isFinite(nVal) && nVal > -9007199254740992 && nVal < 9007199254740992 && Math.floor(nVal) === nVal;
        };
    }
    
    /**
     * Model
     */
    var Subtitle = Backbone.Model.extend({
        defaults: {
            'startTime': '',
            'endTime': '',
            'text': ''
        },
    
        validate: function(attrs) {
            if (!this.get('startTime')) return 'You missed startTime';
            if (!this.get('endTime')) return 'You missed endTime';
            if (!this.get('text')) return 'You missed text';
            if (this.get('startTime') > this.get('endTime')) return 'startTime cannot be greater than endTime';
        },
    
        /**
         * Compare two time periods
         * @param that Subtitle with which we compare the current one
         * @returns {number} positive if {@code this} is greater than {@code that}, negative if {@code this} is less than {@code that}
         * and zero if they are equals or overlaps or one time period contains another.
         */
        equals: function(that) {
            if (!(that instanceof Subtitle)) throw Error('Cannot compare with element that does not belong to Subtitle type');
            if (this.get('startTime') > that.get('endTime')) return 1;
            else if (that.get('startTime') > this.get('endTime')) return -1;
            else return 0;
        },
    
        /**
         *
         * @param moment moment for which we need to find a time period
         * @returns {number} positive if {@code moment} belongs to time period greater than {@code this},
         * negative if {@code moment} belongs to time period less than {@code this}
         * and zero if the curect time period contain the {@code moment}.
         */
        containMoment: function(moment) {
            if (!Number.isInteger(moment)) throw Error('Moment should be an Integer');
    
            if (moment >= this.get('startTime') && moment <= this.get('endTime')) return 0;
            else if (moment < this.get('startTime')) return -1;
            else if (moment > this.get('endTime')) return +1;
            else throw Error('Impossible case :-)');
        }
    });
    
    /**
     * Collection
     */
    var Subtitles = Backbone.Collection.extend({
        model: Subtitle,
        index: 0,
    
        next: function() {
            return this.at(this.index++);
        },
    
        getByMoment: function(moment) {
            return this._binarySearch(this.toArray(), moment);
        },
    
        _binarySearch: function(array, moment) {
            'use strict';
    
            var minIndex = 0;
            var maxIndex = array.length - 1;
            var currentIndex;
            var currentElement;
    
            while (minIndex <= maxIndex) {
                currentIndex = (minIndex + maxIndex) / 2 | 0;
                currentElement = array[currentIndex];
    
                if (currentElement.containMoment(moment) > 0) {
                    minIndex = currentIndex + 1;
                }
                else if (currentElement.containMoment(moment) < 0) {
                    maxIndex = currentIndex - 1;
                }
                else {
                    return array[currentIndex];
                }
            }
    
            throw Error('No subtitle for this moment');
        }
    });
    
    /**
     * Test
     */
    var data = [ 
      { id: '1',
        startTime: 2468,
        endTime: 4743,
        text: 'Here\'s little Ben nodding off.' },
      { id: '2',
        startTime: 5389,
        endTime: 7698,
        text: 'Look at Aunt Monica\'s Little boy.' },
      { id: '3',
        startTime: 7948,
        endTime: 11099,
        text: '-Look, he\'s got Ross\' hair cut.\n-Let me see.' },
      { id: '4',
        startTime: 11948,
        endTime: 14907,
        text: 'Oh, God!\nIs he just the sweetest thing?' },
      { id: '5',
        startTime: 15148,
        endTime: 17946,
        text: 'You must just want\nto kiss him all over.' }
    ];
    var subtitles = new Subtitles();
    subtitles.add(data);
    
    var moment = 3000;
    console.log(subtitles.next().attributes);
    console.log(subtitles.next().attributes);
    console.log(subtitles.next().attributes);
    console.log(subtitles.next().attributes);
    console.log(subtitles.getByMoment(moment).attributes);
    
    if(!Number.isInteger){
    Number.isInteger=函数isInteger(nVal){
    nVal的返回类型==“数字”&&isFinite(nVal)&&nVal>-9007199254740992&&nVal<9007199254740992&&Math.floor(nVal)==nVal;
    };
    }
    /**
    *模型
    */
    var Subtitle=Backbone.Model.extend({
    默认值:{
    “开始时间”:“,
    “结束时间”:“,
    “文本”:”
    },
    验证:函数(attrs){
    如果(!this.get('startTime'))返回“您错过了startTime”;
    如果(!this.get('endTime'))返回“您错过了endTime”;
    如果(!this.get('text'))返回“您错过了文本”;
    如果(this.get('startTime')>this.get('endTime'))返回“startTime不能大于endTime”;
    },
    /**
    *比较两个时间段
    *@param与当前字幕进行比较的字幕
    *@如果{@code this}大于{@code that},则返回{number}正值;如果{@code this}小于{@code that},则返回负值
    *如果它们相等或重叠,或者一个时间段包含另一个时间段,则为零。
    */
    等于:函数(that){
    if(!(Subtitle的那个实例))抛出错误('无法与不属于Subtitle类型的元素进行比较');
    if(this.get('startTime')>that.get('endTime'))返回1;
    否则如果(that.get('startTime')>this.get('endTime')返回-1;
    否则返回0;
    },
    /**
    *
    *@param moment我们需要找到时间段的时刻
    *如果{@code moment}属于大于{@code this}的时间段,则@返回{number}正值,
    *如果{@code moment}属于小于{@code this}的时间段,则为负值
    *如果curect时间段包含{@code moment},则为零。
    */
    控制力矩:功能(力矩){
    if(!Number.isInteger(矩))抛出错误('矩应该是整数');
    如果(矩>=this.get('startTime')&矩this.get('endTime'))返回+1;
    else抛出错误('不可能的情况:-');
    }
    });
    /**
    *收藏
    */
    var Subtitles=Backbone.Collection.extend({
    型号:副标题,,
    索引:0,
    下一步:函数(){
    返回this.at(this.index++);
    },
    getByMoment:函数(矩){
    返回此。\二进制搜索(this.toArray(),矩);
    },
    _二进制搜索:函数(数组、矩){
    "严格使用",;
    var-minIndex=0;
    var maxIndex=array.length-1;
    var电流指数;
    无功电流元件;
    while(minIndex 0){
    最小索引=当前索引+1;
    }
    else if(currentElement.Container力矩(力矩)<0){
    maxIndex=currentIndex-1;
    }
    否则{
    返回数组[currentIndex];
    }
    }
    抛出错误(“此时无字幕”);
    }
    });
    /**
    *试验
    */
    var数据=[
    {id:'1',
    开始时间:2468,
    完时间:4743,
    文字:“小本正在打瞌睡。”,
    {id:'2',
    开始时间:5389,
    完时间:7698,
    短信:“看看莫妮卡阿姨的小男孩。”,
    {id:'3',
    开始时间:7948,
    完时间:11099,
    文字:'-看,他剪了罗斯的头发。\n-让我看看。'},
    {id:'4',
    起始时间:11948,
    结束时间:14907,
    文字:“哦,上帝!\n他是最可爱的吗?”},
    {id:'5',
    开始时间:15148,
    结束时间:17946,
    文字:“你一定是想\n吻他全身。”
    ];
    var subtitles=新字幕();
    副标题。添加(数据);
    var矩=3000;
    console.log(subtitles.next().attributes);
    console.log(subtitles.next().attributes);
    console.log(subtitles.next().attributes);
    console.log(subtitles.next().attributes);
    log(subtitles.getByMoment(矩).attributes);