How store From-To value and result in an array - c#

I want to store some items with fields "fromValue", "ToValue" , "Info" in an array and write a routine to search an input "value" between "FromValue" & "ToValue" and return "Info" field. I need fast searchable container.
FromValue,ToValue,Info
10,20,TX
24,56,NY
input =34 returns NY
Thanks

ok simple, this class defines your generic range.
public class Range<TValue, TInfo>
{
private readonly IComparer<TValue> comparer;
public Range(IComparer<TValue> comparer)
{
this.comparer = comparer;
}
public Range(IComparer<TValue> comparer)
: this(Comparer<TValue>.Default)
{
}
public TValue From { get; set; }
public TValue To { get; set; }
public TInfo Info { get; set; }
public bool InRange(T value, bool inclusive = true)
{
var lowerBound = this.comparer.Compare(value, this.From);
if (lowerBound < 0)
{
return false;
}
else if (!inclusive && lowerBound == 0)
{
return false;
}
var upperBound = this.comparer.Compare(value, this.To);
if (upperBound > 0)
{
return false;
}
else if (!inclusive && upperBound == 0)
{
return false;
}
return true;
}
}
So, you can have a sequence of ranges,
IEnumerable<Range<int, string>> ranges = ...
To find all the info values in range you can do,
var rangesInRange = ranges.Where(r => r.InRange(42)).Select(r => r.Info);
You could make a specialised container to improve this operation.

Class:
public class Information
{
public int FromValue { get; set; }
public int ToValue { get; set; }
public string Info { get; set; }
}
Search:
List<Information> Informations = new List<Information>();
Information infoObj = new Information();
infoObj.FromValue = 10;
infoObj.ToValue = 20;
infoObj.Info = "TX";
Informations.Add(infoObj);
Information infoObj2 = new Information();
infoObj2.FromValue = 24;
infoObj2.ToValue = 56;
infoObj2.Info = "NY";
Informations.Add(infoObj);
//passing sample input which lies between fromvalue and tovalue
int sampleInput = 15;
var result = Informations.FirstOrDefault(x => x.FromValue < sampleInput && sampleInput < x.ToValue);

This is pretty straight forward.
In the most simple scenario just create a class Item
public class Item
{
public int Id { get; set; }
public int FromValue { get; set; }
public int ToValue { get; set; }
public string Info { get; set; }
}
With this you can initialize your collection of type List<T>
List<Item> Items = new List<Item>()
{
new Item() {Id = 1, FromValue = 10, ToValue = 20, Info = "TX"}
new Item() {Id = 2, FromValue = 24, ToValue = 56, Info = "NY"}
new Item() {Id = 3, FromValue = 15, ToValue = 34, Info = "FL"}
};
And with this you can query it to your hearts content.
var itemsFromFlorida = Items.Where(it => it.Info == "FL");

Related

How to prevent items in a list returning "0" when not filled in and they supposed to be "null"?

This was kind of a hard question to ask but this is my problem:
I'm populating a grid with data I obtain from a different class, this class uses a (generic) Model that can represent multiple models:
Model(can represent Vessel or Container):
public class DataGridInstallationRow
{
[Key]
public string Name { get; set; }
//Vessel
public int IMO { get; set; }
public int MMSI { get; set; }
public int EEOI { get; set; }
public int FOC { get; set; }
[Display(Name = "Total Fuel Mass")]
public int TotalFuelMass { get; set; }
[Display(Name = "Average Speed")]
public int AverageSpeed { get; set; }
[Display(Name = "Total Distance Sailed")]
public int TotalDistanceSailed { get; set; }
//Container
[Display(Name = "Generated by Sun")]
public int EnergyGeneratedBySun { get; set; }
[Display(Name = "Generated by Wind")]
public int EnergyGeneratedByWind { get; set; }
[Display(Name = "Generated by Generator")]
public int EnergyGeneratedByGenerator { get; set; }
[Display(Name = "Consumed by EV's")]
public int EnergyConsumedByEV { get; set; }
[Display(Name = "Consumed by Construction Site")]
public int EnergyConsumedByConstructionSite { get; set; }
}
This model is used in my provider:
if (fleet.Type.Equals("Container"))
{
return Enumerable.Range(0, 10).Select(i => new DataGridInstallationRow()
{
Name = $"Container {i}",
EnergyGeneratedBySun = 13,
EnergyGeneratedByWind = 19,
EnergyGeneratedByGenerator = 3,
EnergyConsumedByEV = 15,
EnergyConsumedByConstructionSite = 24
}).ToList();
}
else
{
return Enumerable.Range(0, 10).Select(i => new DataGridInstallationRow()
{
Name = $"Vessel {i}",
IMO = 231,
MMSI = 1344,
EEOI = 8121,
FOC = 123,
TotalFuelMass = 6817,
AverageSpeed = 14,
TotalDistanceSailed = 1560
}).ToList();
}
As u can see, depending on the Fleet.Type, one of the other is filled in. If Fleet.Type is container the object will look like this:
As u can see the properties of "Vessel" is filled in aswell with all "0", I want these to be null instead of "0" because my datagrid is filled with both models now:
Whats best practice to avoid and fix this?
UPDATE
Applied solution of Dogac:
if (fleet.Type.Equals("Container"))
{
return Enumerable.Range(0, 10).Select(i => new DataGridInstallationRow()
{
Name = $"Container {i}",
EnergyGeneratedBySun = 13,
EnergyGeneratedByWind = 19,
EnergyGeneratedByGenerator = 3,
EnergyConsumedByEV = 15,
EnergyConsumedByConstructionSite = 24
}).Where(row =>
{
return row.EnergyGeneratedBySun.HasValue &&
row.EnergyGeneratedByWind.HasValue &&
row.EnergyGeneratedByGenerator.HasValue &&
row.EnergyConsumedByEV.HasValue &&
row.EnergyConsumedByConstructionSite.HasValue;
}).ToList();
}
else
{
return Enumerable.Range(0, 10).Select(i => new DataGridInstallationRow()
{
Name = $"Vessel {i}",
IMO = 231,
MMSI = 1344,
EEOI = 8121,
FOC = 123,
TotalFuelMass = 6817,
AverageSpeed = 14,
TotalDistanceSailed = 1560
}).Where(row =>
{
return row.IMO.HasValue &&
row.MMSI.HasValue &&
row.EEOI.HasValue &&
row.FOC.HasValue &&
row.TotalFuelMass.HasValue &&
row.AverageSpeed.HasValue &&
row.TotalDistanceSailed.HasValue;
}).ToList();
}
Is still not working, im again receiving a list with nullable items.
Thanks in advance
Try making all properties nullable.
Like this:
// Vessel
public int? IMO { get; set; }
public int? MMSI { get; set; }
public int? EEOI { get; set; }
public int? FOC { get; set; }
Edit regarding comment:
Enumerable.Range(0, 10).Select(i => new DataGridInstallationRow()
{
Name = $"Vessel {i}",
IMO = 231,
MMSI = 1344,
EEOI = 8121,
FOC = 123,
TotalFuelMass = 6817,
AverageSpeed = 14,
TotalDistanceSailed = 1560
}).Where(row =>
{
return row.IMO.HasValue &&
row.MMSI.HasValue &&
row.EEOI.HasValue &&
row.FOC.HasValue &&
row.TotalFuelMass.HasValue &&
row.AverageSpeed.HasValue &&
row.TotalDistanceSailed.HasValue;
}).ToList();

Map one class data to another class with iteration

I have a C# project and looking for simple solution for map one class object data to list of another class object.
This is my input class
public class RatesInput
{
public string Type1 { get; set; }
public string Break1 { get; set; }
public string Basic1 { get; set; }
public string Rate1 { get; set; }
public string Type2 { get; set; }
public string Break2 { get; set; }
public string Basic2 { get; set; }
public string Rate2 { get; set; }
public string Type3 { get; set; }
public string Break3 { get; set; }
public string Basic3 { get; set; }
public string Rate3 { get; set; }
}
This is my another class structure
public class RateDetail
{
public string RateType { get; set; }
public decimal Break { get; set; }
public decimal Basic { get; set; }
public decimal Rate { get; set; }
}
it has a object like below. (For easiering the understanding, I use hardcoded values and actually values assign from a csv file)
RatesInput objInput = new RatesInput();
objInput.Type1 = "T";
objInput.Break1 = 100;
objInput.Basic1 = 50;
objInput.Rate1 = 0.08;
objInput.Type2 = "T";
objInput.Break2 = 200;
objInput.Basic2 = 50;
objInput.Rate2 = 0.07;
objInput.Type3 = "T";
objInput.Break3 = 500;
objInput.Basic3 = 50;
objInput.Rate3 = 0.06;
Then I need to assign values to "RateDetail" list object like below.
List<RateDetail> lstDetails = new List<RateDetail>();
//START Looping using foreach or any looping mechanism
RateDetail obj = new RateDetail();
obj.RateType = //first iteration this should be assigned objInput.Type1, 2nd iteration objInput.Type2 etc....
obj.Break = //first iteration this should be assigned objInput.Break1 , 2nd iteration objInput.Break2 etc....
obj.Basic = //first iteration this should be assigned objInput.Basic1 , 2nd iteration objInput.Basic2 etc....
obj.Rate = //first iteration this should be assigned objInput.Rate1, 2nd iteration objInput.Rate2 etc....
lstDetails.Add(obj); //Add obj to the list
//END looping
Is there any way to convert "RatesInput" class data to "RateDetail" class like above method in C#? If yes, how to iterate data set?
Try this:
public class RatesList : IEnumerable<RateDetail>
{
public RatesList(IEnumerable<RatesInput> ratesInputList)
{
RatesInputList = ratesInputList;
}
private readonly IEnumerable<RatesInput> RatesInputList;
public IEnumerator<RateDetail> GetEnumerator()
{
foreach (var ratesInput in RatesInputList)
{
yield return new RateDetail
{
RateType = ratesInput.Type1,
Break = Convert.ToDecimal(ratesInput.Break1, new CultureInfo("en-US")),
Basic = Convert.ToDecimal(ratesInput.Basic1, new CultureInfo("en-US")),
Rate = Convert.ToDecimal(ratesInput.Rate1, new CultureInfo("en-US"))
};
yield return new RateDetail
{
RateType = ratesInput.Type2,
Break = Convert.ToDecimal(ratesInput.Break2),
Basic = Convert.ToDecimal(ratesInput.Basic2),
Rate = Convert.ToDecimal(ratesInput.Rate2, new CultureInfo("en-US"))
};
yield return new RateDetail
{
RateType = ratesInput.Type3,
Break = Convert.ToDecimal(ratesInput.Break3),
Basic = Convert.ToDecimal(ratesInput.Basic3),
Rate = Convert.ToDecimal(ratesInput.Rate3, new CultureInfo("en-US"))
};
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And use:
var list = new RatesList(new List<RatesInput>() { objInput });
foreach (var item in list)
{
Console.WriteLine(item.Basic);
}
You can use Reflection to get the properties info like this:
var props = objInput.GetType().GetProperties();
var types = props.Where(x => x.Name.StartsWith("Type"))
.Select(x => x.GetValue(objInput)).ToList();
var breaks = props.Where(x => x.Name.StartsWith("Break"))
.Select(x => x.GetValue(objInput)).ToList();
var basics = props.Where(x => x.Name.StartsWith("Basic"))
.Select(x => x.GetValue(objInput)).ToList();
var rates = props.Where(x => x.Name.StartsWith("Rate"))
.Select(x => x.GetValue(objInput)).ToList();
List<RateDetail> lstDetails = new List<RateDetail>();
for (int i = 0; i < types.Count; i++)
{
lstDetails.Add(new RateDetail
{
RateType = types[i].ToString(),
Break = Convert.ToDecimal(breaks[i]),
Basic = Convert.ToDecimal(basics[i]),
Rate = Convert.ToDecimal(rates[i])
});
}

Using Contains() to check multiple object values exist in list before adding new list?

How do I check for multiple properties in object to see if it exists in list before adding new object to list? The Contains() doesn't work here, so what should work instead?
What I have here is a large list model and I want to port some data over to a new shorter list model having no duplication values, having unique values.
Thanks..
public class Fee {
public string Year { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public string Vin { get; set; }
public string Color { get; set; }
}
public class Foo {
public string Year { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
List<Fee> modelVehicles = new List<Fee>();
List<Foo> returnVehicles = new List<Foo>();
modelVehicles.Add(new Fee() { Year = "2001", Make = "Ford", Model = "Mustang", Vin = "111", Color = "Green" });
modelVehicles.Add(new Fee() { Year = "2001", Make = "Ford", Model = "Mustang", Vin = "222", Color = "Red" });
modelVehicles.Add(new Fee() { Year = "2001", Make = "Ford", Model = "Mustang", Vin = "333", Color = "Black" });
foreach(var v in modelVehicles)
{
if (returnVehicles.Contains(new Foo { Year = v.Year, Make = v.Make, Model = v.Model }) == false)
{
returnVehicles.Add(
new Foo {
Year = v.Year,
Make = v.Make,
Model = v.Model
}
);
}
}
You can use GroupBy operator, because in fact your operation is grouping:
returnVehicles = modelVehicles.GroupBy(x => new { x.Year, x.Make, x.Model },
x => new Foo() {
Year = x.Year,
Make = x.Make,
Model = x.Model
},
(key, values) => values.First())
.ToList();
And if you implement Equals and GetHashCode for Foo:
public class Foo
{
public string Year { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public override bool Equals(object obj)
{
Foo other = obj as Foo;
if (other == null)
return false;
return string.Equals(Year, other.Year) &&
string.Equals(Make, other.Make) &&
string.Equals(Model, other.Model);
}
public override int GetHashCode()
{
int hash = 13;
hash = (hash * 7) + Year.GetHashCode();
hash = (hash * 7) + Make.GetHashCode();
hash = (hash * 7) + Model.GetHashCode();
return hash;
}
}
this can be simplified:
returnVehicles = modelVehicles.GroupBy(x => new Foo() {
Year = x.Year,
Make = x.Make,
Model = x.Model
},
(key, values) => key)
.ToList();
If all you want to do is get a list of the distinct items, then use Enumerable.Distinct. You just have to create an equality comparer:
class VehicleEqualityComparer: EqualityComparer<Foo>
{
public override int GetHashCode(Foo f)
{
// A reasonably decent hash code for this application.
return (f.Make.GetHashCode() << 16)
| (f.Model.GetHashCode() >> 16)
^ f.Year;
}
public bool Equals(Foo x, Foo y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.Year == y.Year
&& x.Make == y.Make
&& x.Model == y.Model;
}
}
And to get a list of distinct items:
var returnVehicles = modelVehicles.Distinct(new VehicleEqualityComparer()).ToList();

How to compare two generic objects with nested collections

I have been working on a generic method to compare two of the same objects to test wether the values in each one are equal.
I am stuck on trying to compare System.Collection.Generic objects, such as Dictionary, HashSet, LinkedList, Stack, ect...
The one i can compare on is the List collection.
Below is what I have so far. if you can provide a means to compare the generics I'd be greatly appreciative.
~Starts the recursive compare
public static bool FullCompare<T>(this T source, T compareTo, bool ignoreCase)
{
return recursiveCompare(source, compareTo, ignoreCase, true);
}
~The recursive search
private static bool recursiveCompare<T>(T source, T compareTo, bool ignoreCase, bool isEqual)
{
if (source == null || compareTo == null) return isEqual;
if(!isEqual) return isEqual;
Type sourceType = source.GetType();
Type compareToType = compareTo.GetType();
if (sourceType.IsPrimitive || source is string) return Test(source, compareTo, ignoreCase);
var sourceProperties = sourceType.GetProperties();
var compareToProperties = compareToType.GetProperties();
for (var property = 0; property < sourceProperties.Count(); property++ )
{
var sourceProperty = sourceProperties[property];
var compareToProperty = compareToProperties[property];
object sourceValue = sourceProperty.GetValue(source, null);
object compareToValue = compareToProperty.GetValue(compareTo, null);
var sourceElements = sourceValue as IList;
var compareToElements = compareToValue as IList;
if (sourceElements != null)
{
for (var element = 0; element < sourceElements.Count; element++)
{
isEqual = recursiveCompare(sourceElements[element], compareToElements[element], ignoreCase, isEqual);
}
}
else if (typeof(IEnumerable).IsAssignableFrom(sourceProperty.PropertyType))
{
//compare System.Collection.Generic objects
}
else
{
if (sourceProperty.PropertyType.Assembly == sourceType.Assembly)
{
isEqual = recursiveCompare(sourceValue, compareToValue, ignoreCase, isEqual);
}
else
{
isEqual = Test(sourceValue, compareToValue, ignoreCase);
}
}
}
return isEqual;
}
~ The comparison test
private static bool Test<T>(T a, T b, bool ignoreCase)
{
if (a == null && b == null)
{
return true;
}
else if (a == null)
{
return false;
}
else if (b == null)
{
return false;
}
else if (a is string)
{
if (ignoreCase)
{
var aAsString = Convert.ToString(a);
var bAsString = Convert.ToString(b);
return aAsString.EqualsIgnoreCaseAndWhitespace(bAsString);
}
}
return EqualityComparer<T>.Default.Equals(a, b);
}
These are the test cases I am using to test the function
public class A
{
public string TestA { get; set; }
public List<String> ListA { get; set; }
}
public class test
{
public byte? byte1 { get; set; }
//public Dictionary<int, byte> byteDictionary { get; set; }
public HashSet<byte> byteHashSet { get; set; }
public LinkedList<byte> byteLinkedList { get; set; }
public List<byte> byteList { get; set; }
public Queue<byte> byteQueue { get; set; }
public Stack<byte> byteStack { get; set; }
public sbyte? sbyte1 { get; set; }
public short? short1 { get; set; }
public ushort? ushort1 { get; set; }
public int? int1 { get; set; }
public uint? uint1 { get; set; }
public long? long1 { get; set; }
public ulong? ulong1 { get; set; }
public float? float1 { get; set; }
public double? double1 { get; set; }
public char? char1 { get; set; }
public string string1 { get; set; }
public decimal? decimal1 { get; set; }
public bool? bool1 { get; set; }
public DateTime datetime1 { get; set; }
public TimeSpan timespan1 { get; set; }
public string string1Var;
public A objectA { get; set; }
}
var byteAList = new List<byte>();
byteAList.Add(1);
byteAList.Add(2);
var byteBList = new List<byte>();
byteBList.Add(1);
byteBList.Add(2);
//var byteADictionary = new Dictionary<int,byte>();
//byteADictionary.Add(1,1);
//var byteBDictionary = new Dictionary<int,byte>();
//byteBDictionary.Add(1,1);
var dateTimeA = new DateTime(1,1,1,1,1,1);
var dateTimeB = new DateTime(1,1,1,1,1,1);
var timeSpanA = new TimeSpan(1,1,1,1,1);
var timeSpanB = new TimeSpan(1,1,1,1,1);
var aAListAList = new List<string>();
aAListAList.Add("Nel");
aAListAList.Add("Hello");
var aA = new A()
{
TestA = "Jar"
, ListA = aAListAList
};
var aAListBList = new List<string>();
aAListBList.Add("Nel");
aAListBList.Add("Hello");
var aB = new A()
{
TestA = "Jar"
,
ListA = aAListBList
};
var byteHashSetA = new HashSet<byte>();
byteHashSetA.Add(1);
byteHashSetA.Add(2);
var byteHashSetB = new HashSet<byte>();
byteHashSetB.Add(1);
byteHashSetB.Add(2);
var a = new test()
{
byte1 = 1
, byteList = byteAList
//, byteDictionary = byteADictionary
, byteHashSet = byteHashSetA
, sbyte1 = -1
, short1 = -11
, ushort1 = 11
, int1 = -1
, uint1 = 1
, long1 = 1
, ulong1 = 1
, float1 = 1.1F
, double1 = 1.1
//, char1 = 't'
, string1 = "test"
, decimal1 = 1.1M
, bool1 = true
, datetime1 = dateTimeA
, timespan1 = timeSpanA
, string1Var = null
, objectA = aA
};
var a2 = new test()
{
byte1 = 1
,
byteList = byteBList
//,
//byteDictionary = byteBDictionary
,
byteHashSet = byteHashSetB
,
sbyte1 = -1
,
short1 = -11
,
ushort1 = 11
,
int1 = -1
,
uint1 = 1
,
long1 = 1
,
ulong1 = 1
,
float1 = 1.1F
,
double1 = 1.1
,
char1 = 't'
,
string1 = "test"
,
decimal1 = 1.1M
,
bool1 = true
,
datetime1 = dateTimeB
,
timespan1 = timeSpanB
,
string1Var = null
,
objectA = aB
};
var equal = a.FullCompare(a2, true);
I solved the issue by comparing the lengths of the two objects first. then if they are the same then i do a nested loop to compare one list against the other. now this is probably not efficient, but it works.
foreach (var sourceElement in sourceElements) { numOfSourceElements++; }
foreach (var compareToElement in compareToElements) { numOfCompareToElements++; }
if (numOfSourceElements != numOfCompareToElements) isEqual = false;
if (isEqual)
{
foreach (var sourceElement in sourceElements)
{
found = false;
foreach (var compareToElement in compareToElements)
{
if (IsSameAsRecursive(sourceElement, compareToElement, sameAsOptions, isEqual))
{
found = true;
break;
}
}
if (!found) break;
}
isEqual = found;
}

Get the Depth of an object tree of objects with the same type using LAMBDA expression

I have this object:
public class dtHeader
{
public dtHeader ParentHeader { get; set; }
public string HeaderText { get; set; }
public string DataField { get; set; }
public bool Visible { get; set; }
public int DisplayOrder { get; set; }
}
I want to calculate using a lambda expression, the depth of the object, how many layers of the object in itself exists?
I saw this JavaScript post, but I am struggling to translate it to a one line lambda statement.
Lets say the object is as this new dtHeader(){ ParentHeader = null, HeaderText = "col1" };
the result would be 1
and for new dtHeader(){ ParentHeader = new dtHeader(){ ParentHeader = null, HeaderText = "col1" }, HeaderText = "col1" }; the result would be 2
I want to achieve this with a list<dtHeader>, so some of them would have a depth of 1 and others with deeper depths, and want the deepest depth.
_______ITEM_IN_LIST_OBJECT__
______1___2___3___4___5___6_
D 1. |_o_|_o_|_o_|_o_|_o_|_o_|
E 2. |_o_|___|_o_|___|_o_|_o_|
P 3. |___|___|_o_|___|_o_|___|
T 4. |___|___|___|___|_o_|___|
H 5. |___|___|___|___|_o_|___|
It must go infinitly(Until where it allows for objects to heap up inside eachother) deep.
var HeaderLayerCount = lDtCol.Where(n => n.ParentHeader != null)
.Where(n => n.ParentHeader.ParentHeader != null)
.Where(n => n.ParentHeader.ParentHeader.ParentHeader != null);
EDIT:
I just want to add that if you want to work on a specific depth level, for instance, all objects on a depth of 3, you can use this extra recursion function in the class
public class dtCol
{
public dtCol ParentHeader { get; set; }
public string HeaderText { get; set; }
public string DataField { get; set; }
public bool Visible { get; set; }
public int DisplayOrder { get; set; }
public int Depth { get { return ParentHeader != null ? ParentHeader.Depth + 1 : 1; } }
public int CurrentDepth { get; set; } //Set on initialisation
public dtCol getParent(dtCol col, int getDepth) //Gets the parent on a specific level after the first base level (1) else returns the previous not null child
{
return (col.ParentHeader != null && col.ParentHeader.CurrentDepth == getDepth) ? col.ParentHeader : this.getParent(col.ParentHeader, getDepth);
}
}
You can use it like so:
var HeaderLayerCount = lDtCol.OrderByDescending(n => n.Depth).First().Depth;
for (int hlc = 1; hlc <= HeaderLayerCount; hlc++)
{
var headerrow = new List<dtCol>();
//This foreach adds the parent header if not null else adds the not null child
lDtCol.ForEach(n =>
{
var h = n.getParent(n, hlc); //Get Parent, null is returned if parent does not exists
headerrow.Add((h != null) ? h : n); //If parent is null, add base dtCol so that the headers can be merged upwards.
});
//Do what you need with your new single dimensional list of objects
}
Why not implementing a int GetDepth() method on your class, that will reach the top most ancestor, counting each level?
Your query would then be much simpler.
I was outrunned by Frode, kudos to him
I had the same implementation:
public int GetDepth()
{
if (ParentHeader == null)
{
return 1;
}
else return 1 + ParentHeader.GetDepth();
}
using System;
using System.Linq;
namespace ConsoleApplication3
{
public class dtHeader
{
public dtHeader ParentHeader { get; set; }
public string HeaderText { get; set; }
public string DataField { get; set; }
public bool Visible { get; set; }
public int DisplayOrder { get; set; }
public int Depth
{
get
{
// If header has parent, then this depth is parent.depth + 1
if (ParentHeader != null)
return ParentHeader.Depth+1;
else
return 1; // No parent, root is depth 1
}
}
}
class Program
{
static void Main(string[] args)
{
dtHeader[] headers = {
new dtHeader { HeaderText = "dt1" },
new dtHeader { HeaderText = "dt2" },
new dtHeader { HeaderText = "dt3" },
new dtHeader { HeaderText = "dt4" },
new dtHeader { HeaderText = "dt5" }
};
headers[1].ParentHeader = headers[0];
headers[2].ParentHeader = headers[1];
headers[3].ParentHeader = headers[2];
headers[4].ParentHeader = headers[3];
var deepest = headers.OrderByDescending(item=>item.Depth).First();
Console.WriteLine(deepest.Depth+ ", " + deepest.HeaderText);
var runner = deepest;
while (runner.ParentHeader != null)
runner = runner.ParentHeader;
Console.WriteLine("The deepest root header is:" + runner.HeaderText);
}
}
}
Here's a lambda expression to get what you want:
Func<dtHeader, int> getDepth = null;
getDepth = dth =>
{
var depth = 1;
if (dth.ParentHeader != null)
{
depth += getDepth(dth.ParentHeader);
}
return depth;
};
You have to define it in two parts (assigning null & assigning the body) to let recursion work.
I modified Enigmativity's answer to make it work correctly:
Func<dtHeader, int, int> getDepth = null;
getDepth = (dth, depth) =>
{
if (dth.ParentHeader != null)
{
depth = getDepth(dth.ParentHeader, ++depth);
}
return depth;
};
Call it like this:
int depth = getDepth(header, 0)

Categories

Resources