我在LINQ中遇到了一个有趣的问题,我不知道如何解决它
我有一个发送对象(List<Send>
)的列表,其中发送对象具有以下属性
public class Send
{
public string messageName { get; set; }
public string Port { get; set; }
public string Type { get; set; }
}
其中端口可以是PortA, PortB
等。类型只能是"receive"
或"transmit"
,消息名称可以是
0_firstmessage
1_secondmessage
2_thirdmessage
messageName总是在0,1,2….N开头有一个标识符。
我当前的列表中有如下数据。数据中需要注意的几点
- 我的数据已经根据端口进行了排序。所以,PortA数据来了首先是PortB
- 每个类型为"接收"的消息后面跟着0或N个发送消息组
- 每个发送消息总是有一个父接收消息
我的数据:
MESSAGENAME, PORT , TYPE
- 0_message , PortA , receive
- 1_message , PortA , transmit
- 3_message , PortA , transmit
- 7_message , PortA , transmit
- 8_message , PortA , receive
- 9_message , PortA , transmit
- 2_message , PortB , receive
- 4_message , PortB , receive
- 5_message , PortB , transmit
- 6_message , PortB , transmit
- 10_message, PortB , receive
- 11_message , PortB , transmit
我的最终输出应该是这样的。
MESSAGENAME, PORT , TYPE
- 0_message , PortA , receive
- 1_message , PortA , transmit
- 3_message , PortA , transmit
- 7_message , PortA , transmit
- 2_message , PortB , receive
- 4_message , PortB , receive
- 5_message , PortB , transmit
- 6_message , PortB , transmit
- 8_message , PortA , receive
- 9_message , PortA , transmit
- 10_message, PortB , receive
- 11_message , PortB , transmit
我只想基于"接收"类型消息的MESSAGE_NAME进行ORDERBY。孩子"传递"的信息应该保持原样。
我在网上搜索了很多,但我不知道如何编写这个LINQ查询。
这里有一个例子:你可以在这里玩。https://dotnetfiddle.net/DKOOk2
我有一个解决方案,假设您首先收到receive
,然后收到transmit
类型的消息。
int gid=0;
var results = messages.Select(m => new
{ // Rank each message
m.Type.Equals("Receive", StringComparison.InvariantCultureIgnoreCase ) ? ++gid: gid,
message=m
})
.GroupBy(g=>g.groupid) // Group them on Rank
.OrderBy(g=>int.Parse(g.First().message.messageName.Split('_')[0])) // apply Sort
.SelectMany(c=>c.Select(x=>x.message)) // flatten structure .
.ToList() ;
检查工作example
试试下面的代码。
public class Send : IComparable<Send>
{
public string messageName { get; set; }
public string Port { get; set; }
public string Type { get; set; }
public int CompareTo(Send other)
{
int results = 0;
if (this.messageName != other.messageName)
{
results = this.messageName.CompareTo(other.messageName);
}
else
{
if (this.Port != other.Port)
{
results = this.Port.CompareTo(other.Port);
}
else
{
results = this.Type.CompareTo(other.Type);
}
}
return results;
}
}
我希望这个LINQ能帮助你:
var a = mylist.OrderBy(x => x.MESSAGENAME).Where(y => y.TYPE == "receive")
.Concat(mylist.Where(z => z.TYPE!= "receive"));
因此,您将获得IEnumerable,第一个是按消息类型receive发送,第二个是按无序发送。
我还有一个建议给你。您可以添加一个字典,并将您的列表放在key-将是您的发送消息type="receive"的位置,然后您可以简单地按键订购字典。检查此代码:
List<Send> messages = new List<Send>();
messages.Add(new Send() {messageName ="0_message" , Port = "PortA", Type="Receive" });
messages.Add(new Send() {messageName ="1_message" , Port = "PortA", Type="transmit" });
messages.Add(new Send() {messageName ="3_message" , Port = "PortA", Type="transmit" });
messages.Add(new Send() {messageName ="7_message" , Port = "PortA", Type="transmit" });
messages.Add(new Send() {messageName ="8_message" , Port = "PortA", Type="Receive" });
messages.Add(new Send() {messageName ="9_message" , Port = "PortA", Type="transmit" });
messages.Add(new Send() {messageName ="2_message" , Port = "PortB", Type="Receive" });
messages.Add(new Send() {messageName ="4_message" , Port = "PortB", Type="Receive" });
messages.Add(new Send() {messageName ="5_message" , Port = "PortB", Type="transmit" });
messages.Add(new Send() {messageName ="6_message" , Port = "PortB", Type="transmit" });
messages.Add(new Send() {messageName ="10_message" , Port = "PortB", Type="Receive" });
messages.Add(new Send() {messageName ="11_message" , Port = "PortB", Type="transmit" });
Dictionary<Send, List<Send>> myDict = new Dictionary<Send, List<Send>>();
List<Send> mylist2 = new List<Send>();
Send messagename = new Send();
int i = 0;
foreach (Send s in messages)
{
if (s.Type == "Receive" || s.Type == "receive")
{
if (i != 0)
{
myDict.Add(messagename, mylist2);
}
messagename = s;
mylist2 = new List<Send>();
}
else
{
mylist2.Add(s);
}
if(i== messages.Count()-1)
{
myDict.Add(messagename, mylist2);
}
i++;
}
var q = myDict.OrderBy(x => int.Parse(x.Key.messageName.Split('_')[0]));
如果您愿意,您可以将字典转换回列表:
List<Send> newlist = new List<Send>();
foreach (KeyValuePair<Send, List<Send>> k in q)
{
newlist.Add(k.Key);
foreach (Send s in k.Value)
{
newlist.Add(s);
}
}