繁体   English   中英

如何在Javascript数组中的某个对象之前获取最后N个对象?

[英]How to get the last N objects before a certain object in a Javascript array?

我正在尝试在Javascript中实现无限加载项目。 就像在您喜欢的消息传递应用程序中滚动消息时所获得的效果一样。 我有一个像这样的大阵列(+1000个对象):

var array = [
    { id : 1, text: "First"},
    { id : 2, text: "Second"},
    { id : 3, text: "Third"},
    { id : 4, text: "Forth"},
    { id : 5, text: "Fifth"},
    { id : 6, text: "Sixth"},
    { id : 7, text: "Seventh"},
    ...
];

现在我想一次只加载10个项目。 例如,我只显示ID为3039 现在用户希望在30之前看到这些项目。 在id为30对象之前选择最后10个项目的最佳方法是什么? 如前所述,阵列的大小很大,所以性能在这里很重要。

编辑

上面的例子只是一个例子。 我应该能够根据需要一次多次过滤我的数组10个项目。

我想要实现的是加载一个大阵列,但不是一次性加载。 我想一次加载10个项目。 我正在跟踪我的过滤数组中的第一个对象(例如30 ),然后我想在该特定对象之前获取最后10个对象。

编辑2

这是我的观点:

<div ng-repeat="message in messages" class="message-wrapper">
     // Show content of message 
</div>

现在我最初在消息中显示最后10项

$scope.init = function(){        
    var messages = Database.AllMessages(); // This function returns all my messages
    $scope.messages =  messages.length > 10 ? messages.slice(-10) : messages;        
}

现在假设此函数返回的项目是Id为3039 用户向上滚动并希望在30之前看到消息。 那么如何过滤AllMessages()返回的整个数组以获得30消息之前的10个最后一项?

提前感谢任何见解。

您希望尽可能高效地查询数据源。 确保数组首先按id排序:

array.sort(function(a, b) {
  if (a.id === b.id) return 0;
  if (a.id > b.id) return 1;
  return -1;
});

然后,可以执行二进制搜索以查找您要查找的元素的索引:

var search = function(arr, val) {
    if (arr.length === 0) {
        return -1;
    }

    var max = arr.length - 1, min = 0;

    while (max !== min) {
        var index = Math.floor((max + min) / 2);

        if (arr[index].id === val) {
            return index;
        }
        else if (arr[index].id < val) {
            min = index;
        }
        else {
            max = index;
        }
    }
    return arr[index].id === val ? index : -1;
}

// find index of element with desired id.
var index = search(array, 30);

一旦我们知道索引,我们只需选择索引之前/之后的元素:

var rangeMin = index - 10; // Inclusive. 10 is the maximum number of elements you want to render.
var rangeMax = index; // Not inclusive.

if (rangeMin < 0) { rangeMin = 0; }
if (rangeMax > array.length) { rangeMax = array.length; }

var elementsToRender = array.slice(rangeMin, rangeMax);

elementsToRender现在将包含您要渲染的所有元素。

现在让我们说这个函数返回的项是Id为30到39的项。用户向上滚动并希望看到30之前的消息。那么如何过滤AllMessages()返回的整个数组来获得10 30条消息之前的最后一项?

(...)我的观点应该显示项目20至39

假设allMessages包含所有消息(非常大的数组)。
假设ctrl是一个控制器实例
假设ctrl.messages包含当前显示的项目。
假设currentIndex为30
假设stepSize为10
然后,以下代码将messages扩展为包含项目20到39,并将currentIndex设置为20:

currentIndex -= stepSize; // the new first message will have index 20
var extraItems = allMessages.slice(currentIndex, currentIndex+stepSize);
Array.prototype.push.apply(extraItems, ctrl.messages); // append ctrl.messages to extraItems
ctrl.messages = extraItems;

有关Array.prototype.push.apply更多信息,请参阅Mozilla (向下滚动到'合并两个数组')。

这是一个小应用程序来演示它(你必须添加逻辑来保护用户跨越数组边界):

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js"></script>
    <script>
        var myApp = angular.module('myApp', []);

        myApp.controller('MyController', function() {
            var ctrl = this;
            var allMessages = Database.AllMessages();
            var stepSize = 10;
            var currentIndex = allMessages.length - stepSize;

            // show the last 10 messages
            ctrl.messages = allMessages.length > 10 ? allMessages.slice(-10) : allMessages;

            // show ten more messages
            ctrl.showMore = function () {
                currentIndex -= stepSize;
                var extraItems = allMessages.slice(currentIndex, currentIndex+stepSize);
                Array.prototype.push.apply(extraItems, ctrl.messages);
                ctrl.messages = extraItems;
            };
        });
    </script>
</head>
<body ng-app="myApp">

<div ng-controller="MyController as ctrl">
    <table>
        <tr ng-repeat="message in ctrl.messages"><td>{{message.text}}</td></tr>
    </table>
    <button ng-click="ctrl.showMore();">show more</button>
</div>
</body>
</html>

您可以尝试使用以下代码获取id为30的对象而不使用循环:

var array = [
        { id : 1, text: "First"},
        { id : 2, text: "Second"},
        { id : 3, text: "Third"},
        { id : 4, text: "Forth"},
        { id : 5, text: "Fifth"},
        { id : 6, text: "Sixth"},
        { id : 7, text: "Seventh"}
    ];  

    var result = $.grep(array, function(e){ return e.id == 5; });
    console.log(result);

在id为30的对象之前选择最后10个项目的最佳方法是什么?

var index = 30;
var count = 10;
// 10 items before 30 :
array.slice(index-count, index);

我知道我做的这件事对某人有帮助。 这是相关的部分:

$('button.getResult').on('click', function(e) {
  e.preventDefault();
  var limit = $('input.getResult').val();
  if (limit != '' && !isNaN(limit)) {
    var dots = $('ul li');
    if (dots.length > limit) {
      //show the limit as group
      var foundSelected = false;
      var counter = 0;
      for (var i = dots.length - 1; i >= 0; i--) {

        dots.eq(i).addClass('group');
        dots.eq(i + parseInt(limit)).removeClass('group');
        counter++;
        if (i == $('li.selected').index()) {
          foundSelected = true;
        };
        if (foundSelected && counter >= limit) {
          i = -1;
        };

      };
    } else {
      //show all as group
      dots.addClass('group');
    };
  };
  return false;
});

dots基本上就是你的数组,第一个条件就是检查以确保你想要的结果数小于数组的长度。 然后通过数组执行循环(在我的情况下向后)检查重要项目。 如果我找到它,我将布尔值更改为true。

另外,我将每个标记为我迭代时选择的,如果所选索引超出了分页限制,则删除所选标记(以保持分页)。 一旦我找到了重要的项目并且标记了重要项目之后的正确项目数量,我就会停止循环。

当然,您可能无法在您的案例中标记事物,但我认为您可以从中获得一些灵感。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM