如何使用 LINQ 对这些 json 对象进行排序?
How can I order these json objects using LINQ?
有了这样的数据(作为旁注,json 文件中的这些单独的组件被正确地称为什么 - 记录?项目?元素?对象?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 文件。我相信我可以得到这样的计数(假设学生列表是学生列表,如 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 查询中使用它?该计数不是学生 class 的成员,那么 "trick" 可以根据这些计数对结果进行排序吗?
我需要的是同一列表中的两个并排排序。第一个由 WeekOfAssignment 排序,另一个 "beside it" 包含其他人的列表,按他们与当前在第一个查询填充的选中列表框中突出显示的人合作的最少次数排序。
在伪代码中,我最终需要得到的是:
List<Student> orderedStudents = studentlist.OrderBy(WeekOfAssignment);
这会填充 checklistboxStudents。
然后这个:
List<Student> orderedAssistants = studentlist.OrderBy(CountOfTimesWorkedWithSelectedPersonInChecklistboxStudents);
...填充检查列表框助手;因此,每次在 checklistboxStudents 中选择不同的学生时,都必须重新运行第二个查询,并对 checklistboxAssistants 重新排序。
更新
恐怕我没有解释清楚这个问题的本质。它是:
每周有许多 (3) 项作业需要两名学生:"the" 名学生和一名助手。
每个学生都可以扮演任何角色;他们可以进行第 2、3、4、5、6 或 7 次演讲。偶数是学生作业,奇数是助理作业。每个列表都是唯一的 - 接下来将分配给#2 的列表,接下来将分配#3 的列表,等等。
因此,这六个列表中的每一个都是学生超集列表的一个独特子集,在任何给定的一周内大约占每个列表总数的 1/6(他们在下一周移至下一个列表)。
因此我需要将列表 3 中的那些与列表 2 中的那些进行比较,将列表 5 中的那些与列表 4 中的进行比较,将列表 7 中的那些与列表 6 中的进行比较。
有一个跟踪学生数据的学生列表,例如上次给出的作业(#/谈话类型和日期)等。作业列表(上面显示的摘录)包含,对于每个 assignment/week,曾经是 "the" 学生的学生 (StudentID_FK),以及当时担任助理的学生 (AssistantID_FK)。
所以,重新考虑一下,我也许可以像这样命令助手(伪代码):
0) 添加一个 "OptionalOrderingVal" 成员到 Students class:
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.
如果您有这样的模型:
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_FK
和 AssistantID_FK
进行 linq 查询分组,并根据其大小对这些分组进行排序,然后再次加入元素。
根据 StudentID_FK
和 AssistantID_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();
你想要的是按一对学号出现为学生或助教的次数排序,反之亦然。因此:
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>
where T
would be the type used to represent student IDs. Then you can use 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);
}
}
有了这样的数据(作为旁注,json 文件中的这些单独的组件被正确地称为什么 - 记录?项目?元素?对象?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 文件。我相信我可以得到这样的计数(假设学生列表是学生列表,如 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 查询中使用它?该计数不是学生 class 的成员,那么 "trick" 可以根据这些计数对结果进行排序吗?
我需要的是同一列表中的两个并排排序。第一个由 WeekOfAssignment 排序,另一个 "beside it" 包含其他人的列表,按他们与当前在第一个查询填充的选中列表框中突出显示的人合作的最少次数排序。
在伪代码中,我最终需要得到的是:
List<Student> orderedStudents = studentlist.OrderBy(WeekOfAssignment);
这会填充 checklistboxStudents。
然后这个:
List<Student> orderedAssistants = studentlist.OrderBy(CountOfTimesWorkedWithSelectedPersonInChecklistboxStudents);
...填充检查列表框助手;因此,每次在 checklistboxStudents 中选择不同的学生时,都必须重新运行第二个查询,并对 checklistboxAssistants 重新排序。
更新
恐怕我没有解释清楚这个问题的本质。它是:
每周有许多 (3) 项作业需要两名学生:"the" 名学生和一名助手。
每个学生都可以扮演任何角色;他们可以进行第 2、3、4、5、6 或 7 次演讲。偶数是学生作业,奇数是助理作业。每个列表都是唯一的 - 接下来将分配给#2 的列表,接下来将分配#3 的列表,等等。
因此,这六个列表中的每一个都是学生超集列表的一个独特子集,在任何给定的一周内大约占每个列表总数的 1/6(他们在下一周移至下一个列表)。
因此我需要将列表 3 中的那些与列表 2 中的那些进行比较,将列表 5 中的那些与列表 4 中的进行比较,将列表 7 中的那些与列表 6 中的进行比较。
有一个跟踪学生数据的学生列表,例如上次给出的作业(#/谈话类型和日期)等。作业列表(上面显示的摘录)包含,对于每个 assignment/week,曾经是 "the" 学生的学生 (StudentID_FK),以及当时担任助理的学生 (AssistantID_FK)。
所以,重新考虑一下,我也许可以像这样命令助手(伪代码):
0) 添加一个 "OptionalOrderingVal" 成员到 Students class:
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.
如果您有这样的模型:
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_FK
和 AssistantID_FK
进行 linq 查询分组,并根据其大小对这些分组进行排序,然后再次加入元素。
根据 StudentID_FK
和 AssistantID_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();
你想要的是按一对学号出现为学生或助教的次数排序,反之亦然。因此:
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>
where T
would be the type used to represent student IDs. Then you can use 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);
}
}