1

我有一个当前像这样的对象数组,其中条目按日期和时间排序:

var checkin_data = [
    {id: 430, date: "2013-05-05", time: "08:24"},
    {id: 435, date: "2013-05-06", time: "04:22"},
    {id: 436, date: "2013-05-06", time: "05:36"},
    {id: 437, date: "2013-05-06", time: "07:51"},
    {id: 488, date: "2013-05-06", time: "08:08"},
    {id: 489, date: "2013-05-06", time: "10:12"},
    {id: 492, date: "2013-05-06", time: "13:18"},
    {id: 493, date: "2013-05-06", time: "15:55"},
    {id: 494, date: "2013-05-06", time: "18:55"},
    {id: 498, date: "2013-05-06", time: "22:15"},
    {id: 501, date: "2013-05-07", time: "11:40"},
    {id: 508, date: "2013-05-07", time: "18:00"},
    {id: 520, date: "2013-05-08", time: "04:48"},
    {id: 532, date: "2013-05-09", time: "21:11"},
    {id: 492, date: "2013-05-10", time: "11:45"},
    {id: 601, date: "2013-05-11", time: "18:12"}
];

日期代表特定一周中的日期:我想对这个数组进行排序以便将其排列在“行”中,因此需要重新排序数据以像这样布置(注意日期的顺序):

var checkin_data = [
{id: 430, date: "2013-05-05", time: "08:24"},
{id: 435, date: "2013-05-06", time: "04:22"},
{id: 501, date: "2013-05-07", time: "11:40"},
{id: 520, date: "2013-05-08", time: "04:48"},
{id: 532, date: "2013-05-09", time: "21:11"},
{id: 492, date: "2013-05-10", time: "11:45"},
{id: 601, date: "2013-05-11", time: "18:12"},
{id: 436, date: "2013-05-06", time: "05:36"},
{id: 508, date: "2013-05-07", time: "18:00"},
{id: 437, date: "2013-05-06", time: "07:51"},
{id: 488, date: "2013-05-06", time: "08:08"},
{id: 489, date: "2013-05-06", time: "10:12"},
{id: 492, date: "2013-05-06", time: "13:18"},
{id: 493, date: "2013-05-06", time: "15:55"},
{id: 494, date: "2013-05-06", time: "18:55"},
{id: 498, date: "2013-05-06", time: "22:15"}
];

按该顺序获取数据将允许我布置这样的表格:

以表格形式排列的数据

谢谢,任何帮助将不胜感激。

4

6 回答 6

1

这是使用函数方法的建议:

  • 根据日期将列表减少为存储桶数组,然后对该列表进行排序(这就像阅读您在行上获得的表格)
  • 按顺序遍历行,清除未使用的行。

这里:

//first, we collapse the array into an array of buckets by day
half_sorted = checkin_data.reduce(function(accum,cur){ 
    var bucket = new Date(cur.date).getDay();
    accum[bucket].push(cur);
    return accum;
},[[],[],[],[],[],[],[]]).map(function(day){
    return day.sort(function(x,y){ // now we sort each bucket
        return new Date("01-01-1990 "+x.time) - new Date("01-01-1990 "+y.time);
    });    
});
// At this point, we have an array with 7 cells looking like your table
// if we look at its columns.

// finally, we push to the result table.
var result = [];
var daysToClear = 7;
for(var i=0;daysToClear>0;i=(i+1)%7){
    if(half_sorted[i] && half_sorted[i].length > 0){
        result.push(half_sorted[i].pop());
    }else if(half_sorted[i] && half_sorted[i].length === 0){
        half_sorted[i] = null;
        daysToClear--;
    }
}

工作小提琴

于 2013-06-25T00:34:27.830 回答
1

首先,我认为您以错误的方式处理此问题。请在以下代码下方查看我的注释。

完全按照您的要求做,这是一种方法:

// parsing the date strings ourselves avoids time zone problems
function dateFromString(string) {
   var parts = string.split('-');
   return new Date(parseInt(parts[0], 10),
                   parseInt(parts[1], 10) - 1,
                   parseInt(parts[2], 10));
}

上面是一个效用函数。

var i, l, dates = [[], [], [], [], [], [], []], item;
// place the objects into dow-sorted buckets
for (i = 0, l = checkin_data.length; i < l; i += 1) {
   item = checkin_data[i];
   dates[dateFromString(item.date).getDay()].push(item);
}

i = 0;
l = 0;
checkin_data = [];

while (true) { // instead of a for loop to handle the row-wrap manually
   if (dates[i][l]) {
      item = dates[i][l];
      checkin_data.push(item);
   }
   i += 1;
   if (i === 7) {
      if (!item) {
         break; // we had a complete row with no data
      }
      item = undefined;
      l += 1;
      i = 0;
   }
}

checkin_data现在按您要求的顺序排序。

注意:你真的不需要第二个循环,因为它完成了大部分工作,你必须再次使用提供的数组。因此,在您写出表格的例程中,只需使用第一个循环创建的数据结构即可。您当然需要稍微不同的救助策略,因为您不想创建额外的空白行,但我将由您决定。

不过,经过一番思考,我想出了另一种方法,如果你不介意为你的对象添加一个新键:

function dateFromString(string) {
   var parts = string.split('-');
   return new Date(parseInt(parts[0], 10),
                   parseInt(parts[1], 10) - 1,
                   parseInt(parts[2], 10));
}

var i, l, counts = [0, 0, 0, 0, 0, 0, 0], item, dow;

for (i = 0, l = checkin_data.length; i < l; i += 1) {
   item = checkin_data[i];
   dow = dateFromString(item.date).getDay();
   item.sortKey = ++counts[dow] * 7 + dow;
}

checkin_data.sort(function(a, b) {
   return a.sortKey - b.sortKey;
});
于 2013-06-25T01:25:10.873 回答
0

我想出了一个解决方案,也许不是最优雅的,但它正在工作:

var sorted_data = [], elements_to_dump = [], i, j, tmp;

while (checkin_data.length > 0) {

    for (i = 0; i < checkin_data.length; i++) {
        if (checkin_data[i-1]) {
            if (checkin_data[i-1].date === checkin_data[i].date) {
                continue;
            } 
        }
        sorted_data.push(checkin_data[i]);
        elements_to_dump.push(checkin_data[i].id);
    }
    for (j = 0; j < elements_to_dump.length; j++) {
        for (i = 0; i < checkin_data.length; i++) {
            if (checkin_data[i].id === elements_to_dump[j]) {
                tmp = checkin_data.splice(i, 1);
                break;
            }
        }
    }

}
于 2013-06-25T00:36:22.657 回答
0

我想对这个数组进行排序,以便将其排列在“行”中,因此需要将数据重新排序[到这个线性表示中]。按该顺序获取数据将允许我布置表格

不,它不需要。实际上,这一步太多了,中间结果的顺序绝对没有意义。你应该做的是构建一个(工作日)列表(每天条目):

var days = [];
for (var i=0, date=null, day; i<checkin_data.length; i++) {
    var entry = checkin_data[i];
    if (entry.date !== date)
        days.push(day = []);
    day.push(entry);
}

就是这样,你现在有你的二维格式。好吧,也许您需要将其转置以将其放入您想要的表格中,但这也不是太复杂:

var header = [],
    table = [header]; // or create a DOM or a HTML string or whatever
for (var i=0; i<days.length; i++)
    header.push(days[i][0].date /* or the weekday name? */);
for (var r=0; !done; r++) {
    var row = [],
        done = true;
    // create cells:
    for (var i=0; i<days.length; i++)
        if (days[i].length > r) {
            row[i] = days[i][r].time;
            done = false;
        } else
            row[i] = "";
    }
    if (!done)
        table.push(row);
}
于 2013-06-25T01:27:21.483 回答
0

您可以使用Alasql JavaScript 库对数组进行排序。

alasql.fn.WEEKDAY = function(d) {      // User-defined function
    return (new Date(d)).getDay();
};

var res = alasql('SELECT *, WEEKDAY(date) AS dow FROM ? ORDER BY dow', [checkin_data]);

在 jsFiddle试试这个例子。

于 2014-12-18T12:20:55.950 回答
0

你想要做的很简单。这就是我要做的:

var groups = groupBy(checkin_data, "date");      // groups items based on date
var table = zipAll.apply(null, toArray(groups)); // zips corresponding elements
                                                 // of each group into an array

在此之后,您可以按如下方式创建表:

var header = getHeader(groups), rows = map(table, getRow);
document.body.appendChild(getTable(header, rows));

当然,实际代码会大得多(100 多行代码),因为您需要为groupBytoArrayzipAllmapgetHeadergetRowgetTable等编写逻辑。

幸运的是,我有时间去写所有这些东西。因此,您现在有一个工作演示:http: //jsfiddle.net/hZFJw/

我建议您浏览我的代码并尝试了解它是如何工作的。在一个答案中解释太多了。

注意:我的解决方案可能超过 100 行代码。然而,它仍然是一个简单的解决方案,因为:

  1. 生成表格的实际代码只有 4 行长,并且非常易于理解。
  2. 其余代码由可重用函数组成,如groupBy,zipAllmap. 这些功能非常小且易于理解。
  3. 总体而言,通过将程序抽象为可重用的函数,程序的大小增加了。然而,程序的复杂性已大大降低。

您可以像大多数其他答案一样以命令式的方式解决问题,从而获得相同的结果。然而,这样做会使程序更难理解。将我的代码与其他答案进行比较,然后自己看看。

于 2013-06-25T05:01:09.470 回答