【问题标题】:Sorting a threaded conversation对线程对话进行排序
【发布时间】:2015-01-30 03:06:34
【问题描述】:

不知道如何构图这个,但就这样吧。

这是一道排序算法题

我必须使用的工具是服务器上的 PostgresSQL 和 python (2.6) 以及浏览器端的 javascript/jquery

我需要将描述线程对话的数据从 postgres 数据库移动到网页。数据按时间顺序开始,我想在线程中显示

记录数量很少 - 返回的消息不应超过 100 条

所以,作为一个简单的例子,想象一下这张桌子:

ID     Reply_To   Text
===    ========   =============================
1      0          Hello World
2      0          Make me a sandwich
3      1          Hello back
4      2          No chance
5      1          Who are you?
6      5          Me of course

我想到达的终点是

  • 你好世界
    • 你好回来
    • 你是谁?
      • 当然是我
  • 给我做个三明治
    • 没有机会

或者,换一种说法……

ID     Reply_To   Text
===    ========   =============================
1      0          Hello World
3      1          Hello back
5      1          Who are you?
6      5          Me of course
2      0          Make me a sandwich
4      2          No chance

我不是在这里寻求完整的解决方案,我很乐意使用所有 ajax、json 和格式化的东西。

我只是在思考管理排序的最简洁方法时遇到了问题。

SQL? Python? Javascript?

我目前正在使用 Javascript 中的数组排序(没有比我的 Python 技能异常薄弱的事实更好的理由)

编辑 目前我的情况如下:

function byThread(a,b) {
  if (a.reply > b.id && a.reply != 0){
    console.log("Compared id=" + a.id + " with id=" + b.id + " and returned -1 ")
    return -1;
  }
  if (a.id > b.reply && b.reply != 0 ){
    console.log("Compared id=" + a.id + " with id=" + b.id + " and returned 1 ")
    return 1;
  }
  console.log("Compared id=" + a.id + " with id=" + b.id + " and returned 0 ")
  return 0;
}
msg.sort(byThread);

而且它令人沮丧地接近

【问题讨论】:

  • 您可能会发现这很有帮助:graphs。 Postgres 支持 CTE,这让这变得容易多了。
  • 不确定您对“Reply_To”的阅读。如果仍要收集数据,为什么不使用SQL Fiddle 中的“线程”列。由于没有关于您的应用程序上下文的更多上下文,这似乎让生活变得更加轻松。
  • 抱歉@Abecee 在不变得过于冗长的情况下决定要包含多少信息总是很棘手 - 在这种情况下,我无法控制数据结构 - 我被给定的字段所困扰

标签: javascript python sql postgresql sorting


【解决方案1】:

我尝试在纯 sql 中执行此操作,因为我认为这是逻辑应该属于的地方。您需要做的是找到从父母到孩子的 id 列表,然后按此排序。幸运的是,postgres 有可以排序的数组类型,所以我们可以使用递归 CTE:

with recursive threaded(id, reply_to, message, order_path) as (
    select 
        parent.id, 
        parent.reply_to, 
        parent.message, 
        NULL::int[] || parent.id -- create an 1-element array with the parent id
    from conversation parent
    where parent.reply_to is null
    UNION ALL
    select 
        reply.id, 
        reply.reply_to, 
        reply.message, 
        t.order_path || reply.id -- append the reply id to the current path
    from threaded t
    join conversation reply on t.id = reply.reply_to
    where reply.reply_to is not null
)
select * from threaded order by order_path;

结果:

1    NULL    "Hello World"          "{1}"
3    1       "Hello Back"           "{1,3}"
5    1       "Who are you?"         "{1,5}"
6    5       "Me of course"         "{1,5,6}"
2    NULL    "Make me a sandwich"   "{2}"
4    2       "No Chance"            "{2,4}"

我不确定这将如何执行,因此您绝对应该在您的真实数据集上对其进行测试和分析,以确保它没问题。如果不是,也许您可​​以考虑重组数据,并研究在数据库中存储“树”数据的不同方法。有一个名为django-mptt 的 django 库,可以有效地存储和检索树。该概念通常适用于数据库,但用于提取树并确保它们保持完整的算法需要更改您的应用程序逻辑,最好由库处理。

编辑:

我应该提一下,我最初只使用“order_path”的顶级 id 作为单个数字。 This answer 引导我使用一组 id 来保证顺序。

【讨论】:

  • 这很好......我承认现在这让我很头疼,但很可能就是这样
【解决方案2】:

你可以在 JS 端尝试这样的事情。由于这在回复中包含回复,因此很容易从 convoSorted 构建一个 DOM

var convo = [{id: 1, replyTo: 0, text: "hello world"}, 
             {id: 2, replyTo: 0, text: "Make me a sandwich"},
             {id: 3, replyTo: 1, text: "hello back"},
             {id: 4, replyTo: 2, text: "no chance"},
             {id: 5, replyTo: 1, text: "who are you?"},
             {id: 6, replyTo: 5, text: "me of course"},
             {id: 7, replyTo: 0, text: "new question"},
             {id: 8, replyTo: 7, text: "new answer"}];

var convoSorted = [];

function addToReplies(obj, rply){ //recursive function to find the q. to reply to.
  if (obj.id == rply.replyTo){
    obj.replies.push({id: rply.id, text: rply.text, replies: []}); //add to the replies array
  }
  else{
      for (k = 0; k < obj.replies.length; k++){
        addToReplies(obj.replies[k], rply);
      }
  }
}

function sortConvo(){

  for (i = 0; i < convo.length; i++){
    if (convo[i].replyTo == 0){ //if it's not a reply, add to sorted array
      convoSorted.push({ id : convo[i].id, text: convo[i].text, replies: [] });
    }
    else{ //it's a reply, find the question it's replying
      for (j = 0; j < convoSorted.length; j++){
          addToReplies(convoSorted[j], convo[i]);
      }
    }
  }
}

sortConvo();
console.log(convoSorted);

【讨论】:

  • 我喜欢它——我现在正试图在一个排序函数中做到这一点——我确信我离一些真正优雅的逻辑只有一步之遥:)
  • @PerryW 让我们知道您的想法。我很想知道它是如何作为排序函数完成的。
  • 嗨@artm 我已经接近了(请参阅原始问题中的编辑),但随后我在自己的答案中发布了一个尤里卡时刻 - 因为这最终成为一个网页简单地将 DOM 用作文件系统要容易得多,根本不是排序问题
【解决方案3】:

我觉得自己是个白痴——我把这件事弄得太复杂了。

它所需要的只是一点横向思考(本次讨论对此有所帮助)

msgs=[
  {id:1,reply:0,msg:'Hello World'},
  {id:2,reply:0,msg:'Make me a sandwich'},
  {id:3,reply:1,msg:'Hello back'},
  {id:4,reply:2,msg:'No chance'},
  {id:5,reply:1,msg:'Who are you?'},
  {id:6,reply:5,msg:'Me of course'}
];
msgs.sort(function(a,b){
  return a.reply - b.reply;
});

var conversation=$("<div id='threaded'>");
var list = $("<ul>")
  .attr("id","thread_" + msgs[0].reply);
var message = $("<li>")
  .text(msgs[0].msg)
  .attr("id","msg_" + msgs[0].id);
$(list).append(message);
$(conversation).append(list);

for (i=1; i<msgs.length; i++){
  var message = $("<li>")
    .text(msgs[i].msg)
    .attr("id","msg_" + msgs[i].id);
  if ($(conversation).find("#msg_" + msgs[i].reply).length == 0){
    $(conversation).find("ul:eq(0)").append(message);
  } else {
    var list = $("<ul>")
      .attr("id","thread_" + msgs[i].id);
    $(list).append(message);
    $(conversation).find("#msg_" + msgs[i].reply).append(list);
  }
}

有时我忘记了 dom 是多么强大的工具

【讨论】:

    猜你喜欢
    • 2023-03-29
    • 2017-11-21
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    • 2018-02-28
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多