2

This is a tricky one. I an trying to flatten a LINQ object collection. Each item in the collection has the potential of having two collections of other objects. See the example below.

public class DemoClass
{
    public string Name {get; set;}
    public string Address {get; set;}
    public List<Foo> Foos = new List<Foo>();
    public List<Bar> Bars = new List<Bars>();
}

What I had been doing is this using this code block to flatten this object

var output = from d in DemoClassCollection
    from f in d.Foos
    from b in d.Bars
    select new {
        d.Name, 
        d.Address,
        f.FooField1, 
        f.FooField2, 
        b.BarField1,
        b.BarField2
    };

But the problem I'm having is that the result I get is only those DemoClass objects that have objects in the Foos and Bars collections. I need to get all objects in the DemoClass regardless if there are objects in the Foos and Bars collections.

Any help would be greatly appreciated.

Thanks!

1
  • What do you mean by "flatten"? It's not that this is something like a tree and you want to get a sequence. Can you provide an example of some input values and the expected result? Commented Nov 22, 2011 at 16:56

3 Answers 3

4

Sounds like you might want to use DefaultIfEmpty:

var output = from d in DemoClassCollection
    from f in d.Foos.DefaultIfEmpty()
    from b in d.Bars.DefaultIfEmpty()
    select new {
        d.Name, 
        d.Address,
        FooField1 = f == null ? null : f.FooField1, 
        FooField2 = f == null ? null : f.FooField2, 
        BarField1 = b == null ? null : b.BarField1, 
        BarField2 = b == null ? null : b.BarField2
    };
Sign up to request clarification or add additional context in comments.

Comments

3

Looks like a left outer join in Linq will work (http://msdn.microsoft.com/en-us/library/bb397895.aspx

var output = from d in DemoClassCollection
    from f in d.Foos.DefaultIfEmpty()
    from b in d.Bars.DefaultIfEmpty()
    select new {
        d.Name, 
        d.Address,
        f.FooField1, 
        f.FooField2, 
        b.BarField1,
        b.BarField2
    };

Comments

0

I believe you can implement an IComparer to perform custom JOINS or UNIONS in linq based on how you implement the CompareTo() method

From MSDN: http://msdn.microsoft.com/en-us/library/system.icomparable.aspx

using System;
using System.Collections;

  public class Temperature : IComparable 
  {
  // The temperature value
  protected double temperatureF;

    public int CompareTo(object obj) {
    if (obj == null) return 1;

    Temperature otherTemperature = obj as Temperature;
    if (otherTemperature != null) 
        return this.temperatureF.CompareTo(otherTemperature.temperatureF);
    else
       throw new ArgumentException("Object is not a Temperature");
}

public double Fahrenheit 
{
    get 
    {
        return this.temperatureF;
    }
    set {
        this.temperatureF = value;
    }
}

public double Celsius 
{
    get 
    {
        return (this.temperatureF - 32) * (5.0/9);
    }
    set 
    {
        this.temperatureF = (value * 9.0/5) + 32;
    }
  }
 }

 public class CompareTemperatures
{
 public static void Main()
 {
  ArrayList temperatures = new ArrayList();
  // Initialize random number generator.
  Random rnd = new Random();

  // Generate 10 temperatures between 0 and 100 randomly.
  for (int ctr = 1; ctr <= 10; ctr++)
  {
     int degrees = rnd.Next(0, 100);
     Temperature temp = new Temperature();
     temp.Fahrenheit = degrees;
     temperatures.Add(temp);   
  }

  // Sort ArrayList.
  temperatures.Sort();

  foreach (Temperature temp in temperatures)
     Console.WriteLine(temp.Fahrenheit);

} }

// The example displays the following output to the console (individual
// values may vary because they are randomly generated):

// 2 // 7 // 16 // 17 // 31 // 37 // 58 // 66 // 72 // 95

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.