Reputation: 4039
I have an interesting problem in LINQ and I am not sure how to solve it. Here is what my data looks like
I have a list of Send objects(List<Send>
) where Send object has the following properties
public class Send
{
public string messageName { get; set; }
public string Port { get; set; }
public string Type { get; set; }
}
where Port can be PortA, PortB
, etc. Type can only be "receive"
or "transmit"
and messageName can be
0_firstmessage
1_secondmessage
2_thirdmessage
messageName always have an identifier at the start 0,1,2....N.
My current list has data like the following. A few things to note in data
My data:
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
My final output should be like this.
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
I want to ORDERBY based on MESSAGE_NAME for "receive" type messages only. The child "transmit" messages should stay intact.
I searched alot online but I am not sure how to write this LINQ query.
Here is a example: You can play around here. https://dotnetfiddle.net/DKOOk2
Upvotes: 4
Views: 678
Reputation: 629
I have another one suggestion for you. You can add a Dictionary and put your list there where key - will be your Send with message type = "receive" Then you can simply order Dictionary by key. Check this code:
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]));
If you want, you can convert dictionary back to list:
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);
}
}
Upvotes: 0
Reputation: 16956
I have a solution with an assumption that you receive receive
first followed by transmit
type messages.
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() ;
Check working example
Upvotes: 4
Reputation: 629
I hope this LINQ can help you:
var a = mylist.OrderBy(x => x.MESSAGENAME).Where(y => y.TYPE == "receive")
.Concat(mylist.Where(z => z.TYPE!= "receive"));
As a result you will get IEnumerable where first go ordered Sends by message type receive and second - all the rest Sends unordered.
Upvotes: 0
Reputation: 34421
Try this code below.
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;
}
}
Upvotes: 0