Group alternate pairs using Linq
I am trying to group a list of DTOs which contain alternate family pairs to group them in the following format to minimize duplicacy.
Here is the DTO structure which I have currently which has duplicate rows as you can see which can be grouped together based on reverse relation also.
+----------+------------+-----------+
| PersonId | RelativeId | Relation |
+----------+------------+-----------+
| 1 | 2 | "Son" |
| 2 | 1 | "Father" |
| 1 | 3 | "Mother" |
| 3 | 1 | "Son" |
| 2 | 3 | "Husband" |
| 3 | 2 | "Wife" |
+----------+------------+-----------+
into something like this:
+----------+------------+-----------+-----------------+
| PersonId | RelativeId | Relation | ReverseRelation |
+----------+------------+-----------+-----------------+
| 1 | 2 | "Son" | "Father" |
| 1 | 3 | "Mother" | "Son" |
| 2 | 3 | "Husband" | "Wife" |
+----------+------------+-----------+-----------------+
Code which I am trying:
Program.cs
class Program
{
static void Main(string args)
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.GroupBy(x => new { x.PersonId }).ToList();
}
}
RelationDTO.cs
public class RelationDTO
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
public string Relation { get; set; }
}
Relations.cs
public class Relations
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
public string Relation { get; set; }
public string ReverseRelation { get; set; }
}
c# linq
add a comment |
I am trying to group a list of DTOs which contain alternate family pairs to group them in the following format to minimize duplicacy.
Here is the DTO structure which I have currently which has duplicate rows as you can see which can be grouped together based on reverse relation also.
+----------+------------+-----------+
| PersonId | RelativeId | Relation |
+----------+------------+-----------+
| 1 | 2 | "Son" |
| 2 | 1 | "Father" |
| 1 | 3 | "Mother" |
| 3 | 1 | "Son" |
| 2 | 3 | "Husband" |
| 3 | 2 | "Wife" |
+----------+------------+-----------+
into something like this:
+----------+------------+-----------+-----------------+
| PersonId | RelativeId | Relation | ReverseRelation |
+----------+------------+-----------+-----------------+
| 1 | 2 | "Son" | "Father" |
| 1 | 3 | "Mother" | "Son" |
| 2 | 3 | "Husband" | "Wife" |
+----------+------------+-----------+-----------------+
Code which I am trying:
Program.cs
class Program
{
static void Main(string args)
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.GroupBy(x => new { x.PersonId }).ToList();
}
}
RelationDTO.cs
public class RelationDTO
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
public string Relation { get; set; }
}
Relations.cs
public class Relations
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
public string Relation { get; set; }
public string ReverseRelation { get; set; }
}
c# linq
add a comment |
I am trying to group a list of DTOs which contain alternate family pairs to group them in the following format to minimize duplicacy.
Here is the DTO structure which I have currently which has duplicate rows as you can see which can be grouped together based on reverse relation also.
+----------+------------+-----------+
| PersonId | RelativeId | Relation |
+----------+------------+-----------+
| 1 | 2 | "Son" |
| 2 | 1 | "Father" |
| 1 | 3 | "Mother" |
| 3 | 1 | "Son" |
| 2 | 3 | "Husband" |
| 3 | 2 | "Wife" |
+----------+------------+-----------+
into something like this:
+----------+------------+-----------+-----------------+
| PersonId | RelativeId | Relation | ReverseRelation |
+----------+------------+-----------+-----------------+
| 1 | 2 | "Son" | "Father" |
| 1 | 3 | "Mother" | "Son" |
| 2 | 3 | "Husband" | "Wife" |
+----------+------------+-----------+-----------------+
Code which I am trying:
Program.cs
class Program
{
static void Main(string args)
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.GroupBy(x => new { x.PersonId }).ToList();
}
}
RelationDTO.cs
public class RelationDTO
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
public string Relation { get; set; }
}
Relations.cs
public class Relations
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
public string Relation { get; set; }
public string ReverseRelation { get; set; }
}
c# linq
I am trying to group a list of DTOs which contain alternate family pairs to group them in the following format to minimize duplicacy.
Here is the DTO structure which I have currently which has duplicate rows as you can see which can be grouped together based on reverse relation also.
+----------+------------+-----------+
| PersonId | RelativeId | Relation |
+----------+------------+-----------+
| 1 | 2 | "Son" |
| 2 | 1 | "Father" |
| 1 | 3 | "Mother" |
| 3 | 1 | "Son" |
| 2 | 3 | "Husband" |
| 3 | 2 | "Wife" |
+----------+------------+-----------+
into something like this:
+----------+------------+-----------+-----------------+
| PersonId | RelativeId | Relation | ReverseRelation |
+----------+------------+-----------+-----------------+
| 1 | 2 | "Son" | "Father" |
| 1 | 3 | "Mother" | "Son" |
| 2 | 3 | "Husband" | "Wife" |
+----------+------------+-----------+-----------------+
Code which I am trying:
Program.cs
class Program
{
static void Main(string args)
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.GroupBy(x => new { x.PersonId }).ToList();
}
}
RelationDTO.cs
public class RelationDTO
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
public string Relation { get; set; }
}
Relations.cs
public class Relations
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
public string Relation { get; set; }
public string ReverseRelation { get; set; }
}
c# linq
c# linq
edited 2 hours ago
asked 2 hours ago
Kunal Mukherjee
1,1521722
1,1521722
add a comment |
add a comment |
6 Answers
6
active
oldest
votes
I'm not sure whether it is what you need:
public static void Main()
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.Join(relationDTOList,
dto => dto.PersonId + "-" + dto.RelativeId,
dto => dto.RelativeId + "-" + dto.PersonId,
(dto1, dto2) => new Relations
{
PersonId = dto1.PersonId,
RelationId = dto1.RelativeId,
Relation = dto1.Relation,
ReverseRelation = dto2.Relation
}).Distinct(new MyEqualityComparer());
foreach (var g in grp)
Console.WriteLine("{0},{1},{2},{3}", g.PersonId, g.RelationId, g.Relation, g.ReverseRelation);
}
public class MyEqualityComparer : IEqualityComparer<Relations>
{
public bool Equals(Relations x, Relations y)
{
return x.PersonId + "-" + x.RelationId == y.PersonId + "-" + y.RelationId ||
x.PersonId + "-" + x.RelationId == y.RelationId + "-" + y.PersonId;
}
public int GetHashCode(Relations obj)
{
return 0;
}
}
can you explain the overloadedequals
method?
– Kunal Mukherjee
2 hours ago
1
In order to distinct the result list. Because 1-2 should be equal to 2-1, we have to do the equalizer ourselves.
– ojlovecd
1 hour ago
If you assume that the original list is unique you can get a distinct list by filtering such that personId<RelationId.
– Taemyr
8 mins ago
Also please do't stringify just to compare two ints. It's usually better make two comparisons.
– Taemyr
7 mins ago
add a comment |
You can use a join operation like
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.Join(
relationDTOList.Where(v => v.PersonId > v.RelativeId),
v => new Key{PersonId = v.PersonId, RelativeId = v.RelativeId},
v => new Key{PersonId = v.RelativeId, RelativeId = v.PersonId},
(p, q) => new Relations
{
PersonId = p.PersonId,
RelativeId = p.RelativeId,
Relation = p.Relation,
ReverseRelation = q.Relation
}
);
The Key
is:
public struct Key
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
}
add a comment |
I doubt a bit that LINQ is the best choice here as a loop with lookup might be a bit more efficient. However if you really need LINQ, then you could do the following
var relations = from person in relationDTOList
// Match on the exact pair of IDs
join relative in relationDTOList on
new { person.PersonId, person.RelativeId } equals
new { PersonId = relative.RelativeId, RelativeId = relative.PersonId }
// Build the new structure
let relation = new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.PersonId,
ReverseRelation = relative.Relation
}
// Order the pairs to find the duplicates
let ids = new {person.PersonId, relative.PersonId}.OrderBy(x => x).ToArray()
group relation by new { FirstPersonId = ids[0], SecondPersonId = ids[1] }
into relationGroups
// Select only the the first of two duplicates
select relationGroups.First();
What this code does is joins the collection with itself on the matching pairs PersonId
, RelativeId
and then filters out the second record of each pair thus resulting in a collection where the first person found in the list will be considered as parent in the relation.
EDIT: The lookup method I was talking about:
var result = new List<Relations>();
while (relationDTOList.Any())
{
var person = relationDTOList.First();
relationDTOList.RemoveAt(0);
var relative = relationDTOList.Where(x =>
x.PersonId == person.RelativeId && x.RelativeId == person.PersonId)
.Select((x, i) => new {Person = x, Index = i}).FirstOrDefault();
if (relative != null)
{
relationDTOList.RemoveAt(relative.Index);
result.Add(new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.Person.PersonId,
ReverseRelation = relative.Person.Relation
});
}
}
As a note, it empties your original list so you have to make a copy (list.ToList()
) if you need it further in your code.
Running this code turned out to be about six times faster than the method with join
I posted before. I also came up with the following grouping method which runs much faster than the join, however it's still slower than the lookup-and-remove method although they do a very similar thing.
var relations = relationDTOList.GroupBy(person =>
person.PersonId < person.RelativeId
? new {FirstPersonId = person.PersonId, SecondPersonId = person.RelativeId}
: new {FirstPersonId = person.RelativeId, SecondPersonId = person.PersonId})
.Select(group => new Relations {
PersonId = group.First().PersonId,
Relation = group.First().Relation,
RelativeId = group.First().RelativeId,
ReverseRelation = group.Last().Relation
});
Can you also post the loop lookup method you were talking about?
– Kunal Mukherjee
1 hour ago
1
@KunalMukherjee I added the code and some insights I got by running the different versions.
– Imantas
36 mins ago
The groupby version is a nice functional way to do it without emptying the list.
– Kunal Mukherjee
27 mins ago
add a comment |
var query = relationDTOList.OrderBy(x=>x.PersonId).GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new
{
p.PersonId,
p.RelativeId,
p.Relation,
Parrent = al.Where(x => x.PersonId == p.RelativeId && x.RelativeId == p.PersonId).SingleOrDefault().Relation
}
).ToList();
add a comment |
This will do it. But it requires duplicates in the original list.
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new{
p.PersonId,
p.RelativeId,
p.Relation,
ReverseRelation = al.Where( x =>
x.PersonId == p.RelativeId &&
x.RelativeId == p.PersonId )
.SingleOrDefault()
.Relation} ).ToList();
add a comment |
You could Groupby
your relations with a sorted Tuple
of PersonId
and RelativeId
, then pick the first item as first relation and the second item as the reverse relation.
Demo:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Example {
public static class Program {
public static void Main (string args) {
List<RelationDTO> relationDTOList = new List<RelationDTO> {
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
// Group relations into list of lists
var groups = relationDTOList
.GroupBy (r => GetOrderedTuple (r.PersonId, r.RelativeId))
.Select (grp => grp.ToList ()).ToList ();
// Output original relations and their reverse relations
foreach (var group in groups) {
var relation = group.ElementAt (0);
var reverseRelation = group.ElementAt (1);
FormattableString relationOutput = $"PersonId={relation.PersonId} RelativeId={relation.RelativeId} Relation={relation.Relation} ReverseRelation={reverseRelation.Relation}";
Console.WriteLine (relationOutput);
}
}
private static Tuple<int, int> GetOrderedTuple (int n1, int n2) {
if (n1 < n2) {
return Tuple.Create (n1, n2);
}
return Tuple.Create (n2, n1);
}
}
}
Output:
PersonId=1 RelativeId=2 Relation=Son ReverseRelation=Father
PersonId=1 RelativeId=3 Relation=Mother ReverseRelation=Son
PersonId=2 RelativeId=3 Relation=Husband ReverseRelation=Wife
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54017857%2fgroup-alternate-pairs-using-linq%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
I'm not sure whether it is what you need:
public static void Main()
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.Join(relationDTOList,
dto => dto.PersonId + "-" + dto.RelativeId,
dto => dto.RelativeId + "-" + dto.PersonId,
(dto1, dto2) => new Relations
{
PersonId = dto1.PersonId,
RelationId = dto1.RelativeId,
Relation = dto1.Relation,
ReverseRelation = dto2.Relation
}).Distinct(new MyEqualityComparer());
foreach (var g in grp)
Console.WriteLine("{0},{1},{2},{3}", g.PersonId, g.RelationId, g.Relation, g.ReverseRelation);
}
public class MyEqualityComparer : IEqualityComparer<Relations>
{
public bool Equals(Relations x, Relations y)
{
return x.PersonId + "-" + x.RelationId == y.PersonId + "-" + y.RelationId ||
x.PersonId + "-" + x.RelationId == y.RelationId + "-" + y.PersonId;
}
public int GetHashCode(Relations obj)
{
return 0;
}
}
can you explain the overloadedequals
method?
– Kunal Mukherjee
2 hours ago
1
In order to distinct the result list. Because 1-2 should be equal to 2-1, we have to do the equalizer ourselves.
– ojlovecd
1 hour ago
If you assume that the original list is unique you can get a distinct list by filtering such that personId<RelationId.
– Taemyr
8 mins ago
Also please do't stringify just to compare two ints. It's usually better make two comparisons.
– Taemyr
7 mins ago
add a comment |
I'm not sure whether it is what you need:
public static void Main()
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.Join(relationDTOList,
dto => dto.PersonId + "-" + dto.RelativeId,
dto => dto.RelativeId + "-" + dto.PersonId,
(dto1, dto2) => new Relations
{
PersonId = dto1.PersonId,
RelationId = dto1.RelativeId,
Relation = dto1.Relation,
ReverseRelation = dto2.Relation
}).Distinct(new MyEqualityComparer());
foreach (var g in grp)
Console.WriteLine("{0},{1},{2},{3}", g.PersonId, g.RelationId, g.Relation, g.ReverseRelation);
}
public class MyEqualityComparer : IEqualityComparer<Relations>
{
public bool Equals(Relations x, Relations y)
{
return x.PersonId + "-" + x.RelationId == y.PersonId + "-" + y.RelationId ||
x.PersonId + "-" + x.RelationId == y.RelationId + "-" + y.PersonId;
}
public int GetHashCode(Relations obj)
{
return 0;
}
}
can you explain the overloadedequals
method?
– Kunal Mukherjee
2 hours ago
1
In order to distinct the result list. Because 1-2 should be equal to 2-1, we have to do the equalizer ourselves.
– ojlovecd
1 hour ago
If you assume that the original list is unique you can get a distinct list by filtering such that personId<RelationId.
– Taemyr
8 mins ago
Also please do't stringify just to compare two ints. It's usually better make two comparisons.
– Taemyr
7 mins ago
add a comment |
I'm not sure whether it is what you need:
public static void Main()
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.Join(relationDTOList,
dto => dto.PersonId + "-" + dto.RelativeId,
dto => dto.RelativeId + "-" + dto.PersonId,
(dto1, dto2) => new Relations
{
PersonId = dto1.PersonId,
RelationId = dto1.RelativeId,
Relation = dto1.Relation,
ReverseRelation = dto2.Relation
}).Distinct(new MyEqualityComparer());
foreach (var g in grp)
Console.WriteLine("{0},{1},{2},{3}", g.PersonId, g.RelationId, g.Relation, g.ReverseRelation);
}
public class MyEqualityComparer : IEqualityComparer<Relations>
{
public bool Equals(Relations x, Relations y)
{
return x.PersonId + "-" + x.RelationId == y.PersonId + "-" + y.RelationId ||
x.PersonId + "-" + x.RelationId == y.RelationId + "-" + y.PersonId;
}
public int GetHashCode(Relations obj)
{
return 0;
}
}
I'm not sure whether it is what you need:
public static void Main()
{
List<RelationDTO> relationDTOList = new List<RelationDTO>
{
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
var grp = relationDTOList.Join(relationDTOList,
dto => dto.PersonId + "-" + dto.RelativeId,
dto => dto.RelativeId + "-" + dto.PersonId,
(dto1, dto2) => new Relations
{
PersonId = dto1.PersonId,
RelationId = dto1.RelativeId,
Relation = dto1.Relation,
ReverseRelation = dto2.Relation
}).Distinct(new MyEqualityComparer());
foreach (var g in grp)
Console.WriteLine("{0},{1},{2},{3}", g.PersonId, g.RelationId, g.Relation, g.ReverseRelation);
}
public class MyEqualityComparer : IEqualityComparer<Relations>
{
public bool Equals(Relations x, Relations y)
{
return x.PersonId + "-" + x.RelationId == y.PersonId + "-" + y.RelationId ||
x.PersonId + "-" + x.RelationId == y.RelationId + "-" + y.PersonId;
}
public int GetHashCode(Relations obj)
{
return 0;
}
}
answered 2 hours ago
ojlovecd
3,58611218
3,58611218
can you explain the overloadedequals
method?
– Kunal Mukherjee
2 hours ago
1
In order to distinct the result list. Because 1-2 should be equal to 2-1, we have to do the equalizer ourselves.
– ojlovecd
1 hour ago
If you assume that the original list is unique you can get a distinct list by filtering such that personId<RelationId.
– Taemyr
8 mins ago
Also please do't stringify just to compare two ints. It's usually better make two comparisons.
– Taemyr
7 mins ago
add a comment |
can you explain the overloadedequals
method?
– Kunal Mukherjee
2 hours ago
1
In order to distinct the result list. Because 1-2 should be equal to 2-1, we have to do the equalizer ourselves.
– ojlovecd
1 hour ago
If you assume that the original list is unique you can get a distinct list by filtering such that personId<RelationId.
– Taemyr
8 mins ago
Also please do't stringify just to compare two ints. It's usually better make two comparisons.
– Taemyr
7 mins ago
can you explain the overloaded
equals
method?– Kunal Mukherjee
2 hours ago
can you explain the overloaded
equals
method?– Kunal Mukherjee
2 hours ago
1
1
In order to distinct the result list. Because 1-2 should be equal to 2-1, we have to do the equalizer ourselves.
– ojlovecd
1 hour ago
In order to distinct the result list. Because 1-2 should be equal to 2-1, we have to do the equalizer ourselves.
– ojlovecd
1 hour ago
If you assume that the original list is unique you can get a distinct list by filtering such that personId<RelationId.
– Taemyr
8 mins ago
If you assume that the original list is unique you can get a distinct list by filtering such that personId<RelationId.
– Taemyr
8 mins ago
Also please do't stringify just to compare two ints. It's usually better make two comparisons.
– Taemyr
7 mins ago
Also please do't stringify just to compare two ints. It's usually better make two comparisons.
– Taemyr
7 mins ago
add a comment |
You can use a join operation like
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.Join(
relationDTOList.Where(v => v.PersonId > v.RelativeId),
v => new Key{PersonId = v.PersonId, RelativeId = v.RelativeId},
v => new Key{PersonId = v.RelativeId, RelativeId = v.PersonId},
(p, q) => new Relations
{
PersonId = p.PersonId,
RelativeId = p.RelativeId,
Relation = p.Relation,
ReverseRelation = q.Relation
}
);
The Key
is:
public struct Key
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
}
add a comment |
You can use a join operation like
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.Join(
relationDTOList.Where(v => v.PersonId > v.RelativeId),
v => new Key{PersonId = v.PersonId, RelativeId = v.RelativeId},
v => new Key{PersonId = v.RelativeId, RelativeId = v.PersonId},
(p, q) => new Relations
{
PersonId = p.PersonId,
RelativeId = p.RelativeId,
Relation = p.Relation,
ReverseRelation = q.Relation
}
);
The Key
is:
public struct Key
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
}
add a comment |
You can use a join operation like
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.Join(
relationDTOList.Where(v => v.PersonId > v.RelativeId),
v => new Key{PersonId = v.PersonId, RelativeId = v.RelativeId},
v => new Key{PersonId = v.RelativeId, RelativeId = v.PersonId},
(p, q) => new Relations
{
PersonId = p.PersonId,
RelativeId = p.RelativeId,
Relation = p.Relation,
ReverseRelation = q.Relation
}
);
The Key
is:
public struct Key
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
}
You can use a join operation like
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.Join(
relationDTOList.Where(v => v.PersonId > v.RelativeId),
v => new Key{PersonId = v.PersonId, RelativeId = v.RelativeId},
v => new Key{PersonId = v.RelativeId, RelativeId = v.PersonId},
(p, q) => new Relations
{
PersonId = p.PersonId,
RelativeId = p.RelativeId,
Relation = p.Relation,
ReverseRelation = q.Relation
}
);
The Key
is:
public struct Key
{
public int PersonId { get; set; }
public int RelativeId { get; set; }
}
answered 1 hour ago
functor
1145
1145
add a comment |
add a comment |
I doubt a bit that LINQ is the best choice here as a loop with lookup might be a bit more efficient. However if you really need LINQ, then you could do the following
var relations = from person in relationDTOList
// Match on the exact pair of IDs
join relative in relationDTOList on
new { person.PersonId, person.RelativeId } equals
new { PersonId = relative.RelativeId, RelativeId = relative.PersonId }
// Build the new structure
let relation = new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.PersonId,
ReverseRelation = relative.Relation
}
// Order the pairs to find the duplicates
let ids = new {person.PersonId, relative.PersonId}.OrderBy(x => x).ToArray()
group relation by new { FirstPersonId = ids[0], SecondPersonId = ids[1] }
into relationGroups
// Select only the the first of two duplicates
select relationGroups.First();
What this code does is joins the collection with itself on the matching pairs PersonId
, RelativeId
and then filters out the second record of each pair thus resulting in a collection where the first person found in the list will be considered as parent in the relation.
EDIT: The lookup method I was talking about:
var result = new List<Relations>();
while (relationDTOList.Any())
{
var person = relationDTOList.First();
relationDTOList.RemoveAt(0);
var relative = relationDTOList.Where(x =>
x.PersonId == person.RelativeId && x.RelativeId == person.PersonId)
.Select((x, i) => new {Person = x, Index = i}).FirstOrDefault();
if (relative != null)
{
relationDTOList.RemoveAt(relative.Index);
result.Add(new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.Person.PersonId,
ReverseRelation = relative.Person.Relation
});
}
}
As a note, it empties your original list so you have to make a copy (list.ToList()
) if you need it further in your code.
Running this code turned out to be about six times faster than the method with join
I posted before. I also came up with the following grouping method which runs much faster than the join, however it's still slower than the lookup-and-remove method although they do a very similar thing.
var relations = relationDTOList.GroupBy(person =>
person.PersonId < person.RelativeId
? new {FirstPersonId = person.PersonId, SecondPersonId = person.RelativeId}
: new {FirstPersonId = person.RelativeId, SecondPersonId = person.PersonId})
.Select(group => new Relations {
PersonId = group.First().PersonId,
Relation = group.First().Relation,
RelativeId = group.First().RelativeId,
ReverseRelation = group.Last().Relation
});
Can you also post the loop lookup method you were talking about?
– Kunal Mukherjee
1 hour ago
1
@KunalMukherjee I added the code and some insights I got by running the different versions.
– Imantas
36 mins ago
The groupby version is a nice functional way to do it without emptying the list.
– Kunal Mukherjee
27 mins ago
add a comment |
I doubt a bit that LINQ is the best choice here as a loop with lookup might be a bit more efficient. However if you really need LINQ, then you could do the following
var relations = from person in relationDTOList
// Match on the exact pair of IDs
join relative in relationDTOList on
new { person.PersonId, person.RelativeId } equals
new { PersonId = relative.RelativeId, RelativeId = relative.PersonId }
// Build the new structure
let relation = new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.PersonId,
ReverseRelation = relative.Relation
}
// Order the pairs to find the duplicates
let ids = new {person.PersonId, relative.PersonId}.OrderBy(x => x).ToArray()
group relation by new { FirstPersonId = ids[0], SecondPersonId = ids[1] }
into relationGroups
// Select only the the first of two duplicates
select relationGroups.First();
What this code does is joins the collection with itself on the matching pairs PersonId
, RelativeId
and then filters out the second record of each pair thus resulting in a collection where the first person found in the list will be considered as parent in the relation.
EDIT: The lookup method I was talking about:
var result = new List<Relations>();
while (relationDTOList.Any())
{
var person = relationDTOList.First();
relationDTOList.RemoveAt(0);
var relative = relationDTOList.Where(x =>
x.PersonId == person.RelativeId && x.RelativeId == person.PersonId)
.Select((x, i) => new {Person = x, Index = i}).FirstOrDefault();
if (relative != null)
{
relationDTOList.RemoveAt(relative.Index);
result.Add(new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.Person.PersonId,
ReverseRelation = relative.Person.Relation
});
}
}
As a note, it empties your original list so you have to make a copy (list.ToList()
) if you need it further in your code.
Running this code turned out to be about six times faster than the method with join
I posted before. I also came up with the following grouping method which runs much faster than the join, however it's still slower than the lookup-and-remove method although they do a very similar thing.
var relations = relationDTOList.GroupBy(person =>
person.PersonId < person.RelativeId
? new {FirstPersonId = person.PersonId, SecondPersonId = person.RelativeId}
: new {FirstPersonId = person.RelativeId, SecondPersonId = person.PersonId})
.Select(group => new Relations {
PersonId = group.First().PersonId,
Relation = group.First().Relation,
RelativeId = group.First().RelativeId,
ReverseRelation = group.Last().Relation
});
Can you also post the loop lookup method you were talking about?
– Kunal Mukherjee
1 hour ago
1
@KunalMukherjee I added the code and some insights I got by running the different versions.
– Imantas
36 mins ago
The groupby version is a nice functional way to do it without emptying the list.
– Kunal Mukherjee
27 mins ago
add a comment |
I doubt a bit that LINQ is the best choice here as a loop with lookup might be a bit more efficient. However if you really need LINQ, then you could do the following
var relations = from person in relationDTOList
// Match on the exact pair of IDs
join relative in relationDTOList on
new { person.PersonId, person.RelativeId } equals
new { PersonId = relative.RelativeId, RelativeId = relative.PersonId }
// Build the new structure
let relation = new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.PersonId,
ReverseRelation = relative.Relation
}
// Order the pairs to find the duplicates
let ids = new {person.PersonId, relative.PersonId}.OrderBy(x => x).ToArray()
group relation by new { FirstPersonId = ids[0], SecondPersonId = ids[1] }
into relationGroups
// Select only the the first of two duplicates
select relationGroups.First();
What this code does is joins the collection with itself on the matching pairs PersonId
, RelativeId
and then filters out the second record of each pair thus resulting in a collection where the first person found in the list will be considered as parent in the relation.
EDIT: The lookup method I was talking about:
var result = new List<Relations>();
while (relationDTOList.Any())
{
var person = relationDTOList.First();
relationDTOList.RemoveAt(0);
var relative = relationDTOList.Where(x =>
x.PersonId == person.RelativeId && x.RelativeId == person.PersonId)
.Select((x, i) => new {Person = x, Index = i}).FirstOrDefault();
if (relative != null)
{
relationDTOList.RemoveAt(relative.Index);
result.Add(new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.Person.PersonId,
ReverseRelation = relative.Person.Relation
});
}
}
As a note, it empties your original list so you have to make a copy (list.ToList()
) if you need it further in your code.
Running this code turned out to be about six times faster than the method with join
I posted before. I also came up with the following grouping method which runs much faster than the join, however it's still slower than the lookup-and-remove method although they do a very similar thing.
var relations = relationDTOList.GroupBy(person =>
person.PersonId < person.RelativeId
? new {FirstPersonId = person.PersonId, SecondPersonId = person.RelativeId}
: new {FirstPersonId = person.RelativeId, SecondPersonId = person.PersonId})
.Select(group => new Relations {
PersonId = group.First().PersonId,
Relation = group.First().Relation,
RelativeId = group.First().RelativeId,
ReverseRelation = group.Last().Relation
});
I doubt a bit that LINQ is the best choice here as a loop with lookup might be a bit more efficient. However if you really need LINQ, then you could do the following
var relations = from person in relationDTOList
// Match on the exact pair of IDs
join relative in relationDTOList on
new { person.PersonId, person.RelativeId } equals
new { PersonId = relative.RelativeId, RelativeId = relative.PersonId }
// Build the new structure
let relation = new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.PersonId,
ReverseRelation = relative.Relation
}
// Order the pairs to find the duplicates
let ids = new {person.PersonId, relative.PersonId}.OrderBy(x => x).ToArray()
group relation by new { FirstPersonId = ids[0], SecondPersonId = ids[1] }
into relationGroups
// Select only the the first of two duplicates
select relationGroups.First();
What this code does is joins the collection with itself on the matching pairs PersonId
, RelativeId
and then filters out the second record of each pair thus resulting in a collection where the first person found in the list will be considered as parent in the relation.
EDIT: The lookup method I was talking about:
var result = new List<Relations>();
while (relationDTOList.Any())
{
var person = relationDTOList.First();
relationDTOList.RemoveAt(0);
var relative = relationDTOList.Where(x =>
x.PersonId == person.RelativeId && x.RelativeId == person.PersonId)
.Select((x, i) => new {Person = x, Index = i}).FirstOrDefault();
if (relative != null)
{
relationDTOList.RemoveAt(relative.Index);
result.Add(new Relations {
PersonId = person.PersonId,
Relation = person.Relation,
RelativeId = relative.Person.PersonId,
ReverseRelation = relative.Person.Relation
});
}
}
As a note, it empties your original list so you have to make a copy (list.ToList()
) if you need it further in your code.
Running this code turned out to be about six times faster than the method with join
I posted before. I also came up with the following grouping method which runs much faster than the join, however it's still slower than the lookup-and-remove method although they do a very similar thing.
var relations = relationDTOList.GroupBy(person =>
person.PersonId < person.RelativeId
? new {FirstPersonId = person.PersonId, SecondPersonId = person.RelativeId}
: new {FirstPersonId = person.RelativeId, SecondPersonId = person.PersonId})
.Select(group => new Relations {
PersonId = group.First().PersonId,
Relation = group.First().Relation,
RelativeId = group.First().RelativeId,
ReverseRelation = group.Last().Relation
});
edited 36 mins ago
answered 1 hour ago
Imantas
641315
641315
Can you also post the loop lookup method you were talking about?
– Kunal Mukherjee
1 hour ago
1
@KunalMukherjee I added the code and some insights I got by running the different versions.
– Imantas
36 mins ago
The groupby version is a nice functional way to do it without emptying the list.
– Kunal Mukherjee
27 mins ago
add a comment |
Can you also post the loop lookup method you were talking about?
– Kunal Mukherjee
1 hour ago
1
@KunalMukherjee I added the code and some insights I got by running the different versions.
– Imantas
36 mins ago
The groupby version is a nice functional way to do it without emptying the list.
– Kunal Mukherjee
27 mins ago
Can you also post the loop lookup method you were talking about?
– Kunal Mukherjee
1 hour ago
Can you also post the loop lookup method you were talking about?
– Kunal Mukherjee
1 hour ago
1
1
@KunalMukherjee I added the code and some insights I got by running the different versions.
– Imantas
36 mins ago
@KunalMukherjee I added the code and some insights I got by running the different versions.
– Imantas
36 mins ago
The groupby version is a nice functional way to do it without emptying the list.
– Kunal Mukherjee
27 mins ago
The groupby version is a nice functional way to do it without emptying the list.
– Kunal Mukherjee
27 mins ago
add a comment |
var query = relationDTOList.OrderBy(x=>x.PersonId).GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new
{
p.PersonId,
p.RelativeId,
p.Relation,
Parrent = al.Where(x => x.PersonId == p.RelativeId && x.RelativeId == p.PersonId).SingleOrDefault().Relation
}
).ToList();
add a comment |
var query = relationDTOList.OrderBy(x=>x.PersonId).GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new
{
p.PersonId,
p.RelativeId,
p.Relation,
Parrent = al.Where(x => x.PersonId == p.RelativeId && x.RelativeId == p.PersonId).SingleOrDefault().Relation
}
).ToList();
add a comment |
var query = relationDTOList.OrderBy(x=>x.PersonId).GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new
{
p.PersonId,
p.RelativeId,
p.Relation,
Parrent = al.Where(x => x.PersonId == p.RelativeId && x.RelativeId == p.PersonId).SingleOrDefault().Relation
}
).ToList();
var query = relationDTOList.OrderBy(x=>x.PersonId).GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new
{
p.PersonId,
p.RelativeId,
p.Relation,
Parrent = al.Where(x => x.PersonId == p.RelativeId && x.RelativeId == p.PersonId).SingleOrDefault().Relation
}
).ToList();
edited 1 hour ago
answered 1 hour ago
ElConrado
572524
572524
add a comment |
add a comment |
This will do it. But it requires duplicates in the original list.
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new{
p.PersonId,
p.RelativeId,
p.Relation,
ReverseRelation = al.Where( x =>
x.PersonId == p.RelativeId &&
x.RelativeId == p.PersonId )
.SingleOrDefault()
.Relation} ).ToList();
add a comment |
This will do it. But it requires duplicates in the original list.
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new{
p.PersonId,
p.RelativeId,
p.Relation,
ReverseRelation = al.Where( x =>
x.PersonId == p.RelativeId &&
x.RelativeId == p.PersonId )
.SingleOrDefault()
.Relation} ).ToList();
add a comment |
This will do it. But it requires duplicates in the original list.
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new{
p.PersonId,
p.RelativeId,
p.Relation,
ReverseRelation = al.Where( x =>
x.PersonId == p.RelativeId &&
x.RelativeId == p.PersonId )
.SingleOrDefault()
.Relation} ).ToList();
This will do it. But it requires duplicates in the original list.
var result = relationDTOList
.Where(v => v.PersonId < v.RelativeId)
.GroupJoin(relationDTOList,
p => p.PersonId,
a => a.RelativeId,
(p, al) =>
new{
p.PersonId,
p.RelativeId,
p.Relation,
ReverseRelation = al.Where( x =>
x.PersonId == p.RelativeId &&
x.RelativeId == p.PersonId )
.SingleOrDefault()
.Relation} ).ToList();
answered 53 mins ago
tomRatzfatz
112
112
add a comment |
add a comment |
You could Groupby
your relations with a sorted Tuple
of PersonId
and RelativeId
, then pick the first item as first relation and the second item as the reverse relation.
Demo:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Example {
public static class Program {
public static void Main (string args) {
List<RelationDTO> relationDTOList = new List<RelationDTO> {
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
// Group relations into list of lists
var groups = relationDTOList
.GroupBy (r => GetOrderedTuple (r.PersonId, r.RelativeId))
.Select (grp => grp.ToList ()).ToList ();
// Output original relations and their reverse relations
foreach (var group in groups) {
var relation = group.ElementAt (0);
var reverseRelation = group.ElementAt (1);
FormattableString relationOutput = $"PersonId={relation.PersonId} RelativeId={relation.RelativeId} Relation={relation.Relation} ReverseRelation={reverseRelation.Relation}";
Console.WriteLine (relationOutput);
}
}
private static Tuple<int, int> GetOrderedTuple (int n1, int n2) {
if (n1 < n2) {
return Tuple.Create (n1, n2);
}
return Tuple.Create (n2, n1);
}
}
}
Output:
PersonId=1 RelativeId=2 Relation=Son ReverseRelation=Father
PersonId=1 RelativeId=3 Relation=Mother ReverseRelation=Son
PersonId=2 RelativeId=3 Relation=Husband ReverseRelation=Wife
add a comment |
You could Groupby
your relations with a sorted Tuple
of PersonId
and RelativeId
, then pick the first item as first relation and the second item as the reverse relation.
Demo:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Example {
public static class Program {
public static void Main (string args) {
List<RelationDTO> relationDTOList = new List<RelationDTO> {
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
// Group relations into list of lists
var groups = relationDTOList
.GroupBy (r => GetOrderedTuple (r.PersonId, r.RelativeId))
.Select (grp => grp.ToList ()).ToList ();
// Output original relations and their reverse relations
foreach (var group in groups) {
var relation = group.ElementAt (0);
var reverseRelation = group.ElementAt (1);
FormattableString relationOutput = $"PersonId={relation.PersonId} RelativeId={relation.RelativeId} Relation={relation.Relation} ReverseRelation={reverseRelation.Relation}";
Console.WriteLine (relationOutput);
}
}
private static Tuple<int, int> GetOrderedTuple (int n1, int n2) {
if (n1 < n2) {
return Tuple.Create (n1, n2);
}
return Tuple.Create (n2, n1);
}
}
}
Output:
PersonId=1 RelativeId=2 Relation=Son ReverseRelation=Father
PersonId=1 RelativeId=3 Relation=Mother ReverseRelation=Son
PersonId=2 RelativeId=3 Relation=Husband ReverseRelation=Wife
add a comment |
You could Groupby
your relations with a sorted Tuple
of PersonId
and RelativeId
, then pick the first item as first relation and the second item as the reverse relation.
Demo:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Example {
public static class Program {
public static void Main (string args) {
List<RelationDTO> relationDTOList = new List<RelationDTO> {
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
// Group relations into list of lists
var groups = relationDTOList
.GroupBy (r => GetOrderedTuple (r.PersonId, r.RelativeId))
.Select (grp => grp.ToList ()).ToList ();
// Output original relations and their reverse relations
foreach (var group in groups) {
var relation = group.ElementAt (0);
var reverseRelation = group.ElementAt (1);
FormattableString relationOutput = $"PersonId={relation.PersonId} RelativeId={relation.RelativeId} Relation={relation.Relation} ReverseRelation={reverseRelation.Relation}";
Console.WriteLine (relationOutput);
}
}
private static Tuple<int, int> GetOrderedTuple (int n1, int n2) {
if (n1 < n2) {
return Tuple.Create (n1, n2);
}
return Tuple.Create (n2, n1);
}
}
}
Output:
PersonId=1 RelativeId=2 Relation=Son ReverseRelation=Father
PersonId=1 RelativeId=3 Relation=Mother ReverseRelation=Son
PersonId=2 RelativeId=3 Relation=Husband ReverseRelation=Wife
You could Groupby
your relations with a sorted Tuple
of PersonId
and RelativeId
, then pick the first item as first relation and the second item as the reverse relation.
Demo:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Example {
public static class Program {
public static void Main (string args) {
List<RelationDTO> relationDTOList = new List<RelationDTO> {
new RelationDTO { PersonId = 1, RelativeId = 2, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 1, Relation = "Father" },
new RelationDTO { PersonId = 1, RelativeId = 3, Relation = "Mother" },
new RelationDTO { PersonId = 3, RelativeId = 1, Relation = "Son" },
new RelationDTO { PersonId = 2, RelativeId = 3, Relation = "Husband" },
new RelationDTO { PersonId = 3, RelativeId = 2, Relation = "Wife" },
};
// Group relations into list of lists
var groups = relationDTOList
.GroupBy (r => GetOrderedTuple (r.PersonId, r.RelativeId))
.Select (grp => grp.ToList ()).ToList ();
// Output original relations and their reverse relations
foreach (var group in groups) {
var relation = group.ElementAt (0);
var reverseRelation = group.ElementAt (1);
FormattableString relationOutput = $"PersonId={relation.PersonId} RelativeId={relation.RelativeId} Relation={relation.Relation} ReverseRelation={reverseRelation.Relation}";
Console.WriteLine (relationOutput);
}
}
private static Tuple<int, int> GetOrderedTuple (int n1, int n2) {
if (n1 < n2) {
return Tuple.Create (n1, n2);
}
return Tuple.Create (n2, n1);
}
}
}
Output:
PersonId=1 RelativeId=2 Relation=Son ReverseRelation=Father
PersonId=1 RelativeId=3 Relation=Mother ReverseRelation=Son
PersonId=2 RelativeId=3 Relation=Husband ReverseRelation=Wife
edited 45 mins ago
answered 1 hour ago
RoadRunner
10.5k31340
10.5k31340
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54017857%2fgroup-alternate-pairs-using-linq%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown