fork(9) download
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4.  
  5. static class Program
  6. {
  7. static void Main(string[] args)
  8. {
  9. var ax = new[] {
  10. new { id = 1, name = "John" },
  11. new { id = 2, name = "Sue" } };
  12. var bx = new[] {
  13. new { id = 1, surname = "Doe" },
  14. new { id = 3, surname = "Smith" } };
  15.  
  16. ax.FullOuterJoin(
  17. bx, a => a.id, b => b.id,
  18. (a, b, id) => new { a.name, b.surname },
  19. new { id = -1, name = "(no firstname)" },
  20. new { id = -2, surname = "(no surname)" }
  21. )
  22. .ToList().ForEach(Console.WriteLine);
  23. }
  24. }
  25.  
  26. internal static class MyExtensions
  27. {
  28. internal static IList<TR> FullOuterGroupJoin<TA, TB, TK, TR>(
  29. this IEnumerable<TA> a,
  30. IEnumerable<TB> b,
  31. Func<TA, TK> selectKeyA,
  32. Func<TB, TK> selectKeyB,
  33. Func<IEnumerable<TA>, IEnumerable<TB>, TK, TR> projection,
  34. IEqualityComparer<TK> cmp = null)
  35. {
  36. cmp = cmp?? EqualityComparer<TK>.Default;
  37. var alookup = a.ToLookup(selectKeyA, cmp);
  38. var blookup = b.ToLookup(selectKeyB, cmp);
  39.  
  40. var keys = new HashSet<TK>(alookup.Select(p => p.Key), cmp);
  41. keys.UnionWith(blookup.Select(p => p.Key));
  42.  
  43. var join = from key in keys
  44. let xa = alookup[key]
  45. let xb = blookup[key]
  46. select projection(xa, xb, key);
  47.  
  48. return join.ToList();
  49. }
  50.  
  51. internal static IList<TR> FullOuterJoin<TA, TB, TK, TR>(
  52. this IEnumerable<TA> a,
  53. IEnumerable<TB> b,
  54. Func<TA, TK> selectKeyA,
  55. Func<TB, TK> selectKeyB,
  56. Func<TA, TB, TK, TR> projection,
  57. TA defaultA = default(TA),
  58. TB defaultB = default(TB),
  59. IEqualityComparer<TK> cmp = null)
  60. {
  61. cmp = cmp?? EqualityComparer<TK>.Default;
  62. var alookup = a.ToLookup(selectKeyA, cmp);
  63. var blookup = b.ToLookup(selectKeyB, cmp);
  64.  
  65. var keys = new HashSet<TK>(alookup.Select(p => p.Key), cmp);
  66. keys.UnionWith(blookup.Select(p => p.Key));
  67.  
  68. var join = from key in keys
  69. from xa in alookup[key].DefaultIfEmpty(defaultA)
  70. from xb in blookup[key].DefaultIfEmpty(defaultB)
  71. select projection(xa, xb, key);
  72.  
  73. return join.ToList();
  74. }
  75. }
  76.  
Success #stdin #stdout 0.07s 34352KB
stdin
Standard input is empty
stdout
{ name = John, surname = Doe }
{ name = Sue, surname = (no surname) }
{ name = (no firstname), surname = Smith }