如何使用LINQ订购这些json对象?

时间:2016-03-04 20:12:32

标签: c# json linq generic-list

使用这样的数据(作为旁注,json文件中的这些单独组件正确地称为什么 - 记录?items?elements?objects?jsonpiecesparts?):

[
  {
    "WeekOfAssignment": "2016-04-04T00:00:00",
    "TalkType": 1,
    "StudentID_FK": 32,
    "AssistantID_FK": 0,
    "CounselPoint": 10,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  },
  {
    "WeekOfAssignment": "2016-04-11T00:00:00",
    "TalkType": 1,
    "StudentID_FK": 43,
    "AssistantID_FK": 0,
    "CounselPoint": 39,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  },
  {
    "WeekOfAssignment": "2016-04-11T00:00:00",
    "TalkType": 2,
    "StudentID_FK": 44,
    "AssistantID_FK": 40,
    "CounselPoint": 12,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  },
  {
    "WeekOfAssignment": "2016-04-11T00:00:00",
    "TalkType": 4,
    "StudentID_FK": 4,
    "AssistantID_FK": 24,
    "CounselPoint": 23,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  },
  {
    "WeekOfAssignment": "2016-04-11T00:00:00",
    "TalkType": 6,
    "StudentID_FK": 1,
    "AssistantID_FK": 41,
    "CounselPoint": 42,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  },
  {
    "WeekOfAssignment": "2016-04-25T00:00:00",
    "TalkType": 1,
    "StudentID_FK": 19,
    "AssistantID_FK": 0,
    "CounselPoint": 2,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  },
  {
    "WeekOfAssignment": "2016-04-25T00:00:00",
    "TalkType": 2,
    "StudentID_FK": 13,
    "AssistantID_FK": 12,
    "CounselPoint": 41,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  },
  {
    "WeekOfAssignment": "2016-04-25T00:00:00",
    "TalkType": 4,
    "StudentID_FK": 20,
    "AssistantID_FK": 42,
    "CounselPoint": 11,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  },
  {
    "WeekOfAssignment": "2016-04-25T00:00:00",
    "TalkType": 6,
    "StudentID_FK": 36,
    "AssistantID_FK": 39,
    "CounselPoint": 31,
    "HasBeenEmailed": false,
    "SlipHasBeenPrinted": false
  }
]

...我想根据StudentID_FK与AssistantID_FK合作的次数来命令这些对象(或者他们被称为的任何对象),这两个对象在列表顶部被分配在一起的次数最少。 IOW,两个从未被分配在一起的应该是有序列表中的第一个项目,而那些已经被分配在一起最多的那些应该在底部。

注意:一次出现为“StudentID_FK”的人下次可能会被表示为“AssistantID_FK”,反之亦然。

要确定这一点,需要查询整个json文件。我相信我可以得到这样的计数(假设studentlist是学生列表,如json文件中所示):

int countOfTimesWorkedTogether = GetCountOfTimesWorkedTogether(student1, student2);

private int GetCountOfTimesWorkedTogether(int student, int assistant)
{
    int StudentAndAssistant = studentlist.Where(s => s.StudentID_FK == student && a => a.AssistantID_FK == assistant).Count();
    int AssistantAndStudent = studentlist.Where(s => s.StudentID_FK == assistant && a => a.AssistantID_FK == student).Count();
    return StudentAndAssistant + AssistantAndStudent;
}

...但是我如何在列表的LINQ查询中使用它?伯爵不是学生班的成员,那么根据这些计数可以采用什么“技巧”来订购结果呢?

我需要的是来自同一列表的两个并排排序。第一个由WeekOfAssignment排序,另一个“旁边”包含其他人的列表,按最少的时间排序,他们与当前在第一个查询中填充的checkedlistbox中突出显示的人一起工作。

在伪代码中,我最终需要的是:

List<Student> orderedStudents = studentlist.OrderBy(WeekOfAssignment);

填充checklistboxStudents。

然后这个:

List<Student> orderedAssistants = studentlist.OrderBy(CountOfTimesWorkedWithSelectedPersonInChecklistboxStudents);

...填充checklistboxAssistants;因此,每次在checklistboxStudents中选择不同的学生时,必须重新运行第二个查询,并重新排序checklistboxAssistants。

更新

我担心我没有清楚地解释这个问题的本质。它是:

每周都有一(3)份作业需要两名学生:“学生”和助理。

每个学生都可以扮演任何角色;他们可以给出讲话2,3,4,5,6或7.偶数是学生作业,奇数是辅助作业。每个列表都是唯一的 - 那些预定将被分配为#2的列表,那些将被分配为#3的列表,等等。

因此,六个列表中的每一个都是学生超集列表的唯一子集,在任何给定的一周中,每个列表的总数约为1/6(它们将在下一周移动到下一个列表)。

所以我需要将列表3中的列表与列表2中的列表进行比较,将列表5中​​的列表与列表4中的列表进行比较,将列表7中的列表与列表6中的列表进行比较。

有一个学生列表可以跟踪学生的数据,例如给出的最后一个作业(#/谈话类型和日期)等。作业清单(摘录如上所示)包含作业/周,作为“学生”(StudentID_FK)的学生,以及作为该学生助理的学生(AssistantID_FK)。

所以,重新思考它,我或许可以订购这样的助手(伪代码):

0)将“OptionalOrderingVal”成员添加到Students类:

public int OptionalOrderingVal { get; set; }

首先,根据下一个分配类型获取初始助手列表,按上次分配日期排序;例如,对于分配#3,它支持#2:

var RVAssistantsList = studentlist.Where(t => t.talkType == 3).OrderBy(w => weekOfLastAssignment);

接下来,创建该子列表的新版本,填充OptionalOrderingVal成员:

int countOfAssignmentsWithStudent = 0;
int StudentId = comboboxRVStudent.SelectedValue;
foreach (Student assistant in RVAssistantsList)
{
    countOfAssignmentsWithStudent = assignmentsList.Where(StudentID_FK == StudentId && AssistantID_FK == AssistantId || StudentID_FK == AssistantId && AssistantID_FK == StudentId);
    assistant.OptionalOrderingVal = countOfAssignmentsWithStudent;
}

然后,按新值排序助理列表:

RVAssistantsList = RVAssistantsList
    .OrderBy(o => o.OptionalOrderingVal)
    .ThenBy(w => w.WeekOfLastAssignment)
    .ToList();

最后,将该列表分配给相应的检查表:

checklistboxRVAssistants.Items = RVAssistantsList;

我可以称之为kludgelent或eligy; YMMV。

2 个答案:

答案 0 :(得分:1)

如果您有这样的模型:

public class Student
{
    public DateTime WeekOfAssignment { get; set; }
    public int TalkType { get; set; }
    public int StudentID_FK { get; set; }
    public int AssistantID_FK { get; set; }
    public int CounselPoint { get; set; }
    public bool HasBeenEmailed { get; set; }
    public bool SlipHasBeenPrinted { get; set; }
}

您可以使用匿名类型按属性StudentID_FKAssistantID_FK进行linq查询分组,并根据其大小对此组进行排序,然后再次加入元素。

根据StudentID_FKAssistantID_FK对出现在列表中的次数,排序的元素排序,首先是最低的次数:

var result = studentlist.GroupBy(m => new 
                                { 
                                    A = Math.Min(m.StudentID_FK, m.AssistantID_FK),  // This gets pairs like (1, 2) and (2, 1)
                                    B = Math.Max(m.StudentID_FK, m.AssistantID_FK)   // as the same (1, 2)
                                })
                    .OrderBy(g => g.Count())
                    .SelectMany(g => g)
                    .ToList();

答案 1 :(得分:1)

您想要的是按一对学生ID作为学生或助理出现的次数进行排序,反之亦然。因此:

        var orderedAssistants = studentlist
            .OrderBy(a => GetCountOfTimesWorkedTogether(studentlist, a.StudentID_FK, a.AssistantID_FK))
            .ToList();

使用

    private static int GetCountOfTimesWorkedTogether(IEnumerable<Student> studentList, int id1, int id2)
    {
        var count = studentList.Where(s => s.StudentID_FK == id1 && s.AssistantID_FK == id2 || s.StudentID_FK == id2 && s.AssistantID_FK == id1).Count();
        return count;
    }

但请注意,这可以是学生人数的二次方。你要找的是两个学生一起工作的时间 - 学生+助理,反之亦然。表示与订单无关的组合的标准方法是HashSet<T>,其中T将是用于表示学生ID的类型。然后,您可以使用HashSet<T>.CreateSetComparer()按内容相等性对集合进行分组:

因此,以下不应该是二次的:

        var orderedAssistants = studentlist
            .GroupBy(s => (new[] { s.AssistantID_FK, s.StudentID_FK }).ToSet(), HashSet<int>.CreateSetComparer())
            .OrderBy(g => g.Count())
            .SelectMany(g => g)
            .ToList();

使用

public static class EnumerableExtensions
{
    public static HashSet<T> ToSet<T>(this IEnumerable<T> source)
    {
        return new HashSet<T>(source);
    }
}