Compare two list's values and get the difference - c#

I created a method that compares two lists' values and outputs the difference:
public static List<OT_Contact> Comparer(
List<OT_Contact> security_owner,
List<OT_Contact> borrower)
{
List<OT_Contact> nonborrowertrustor = security_owner.Except(borrower).ToList();
foreach (var nbt_list in nonborrowertrustor)
{
var list = nbt_list;
}
return nonborrowertrustor;
}
Can anyone tell me if there is something wrong with my code and how can I assign it to a variable, for example:
var result = Comparer(list1, list2);

Why are you not using Linq?
var trustys = security_owner
.Where(o => !borrower.Any(b=> b.Name == o.Name /* && compare more attributes from o and b */))
.ToList();
return trustys;
this will filter all items from security owner which aren't in borrower, using
(b=> b.Name == o.Name && .....)
as "equality measure".
Example:
using System.Collections.Generic;
using System.Linq;
internal class Program
{
public class OT_Contact
{
public int Age;
public string Email;
public string Name;
public OT_Contact(string name, string email, int age = int.MinValue)
{
Name = name;
Email = email;
Age = age;
}
public override string ToString()
{
return ($"{Name} {Email} " + (Age != int.MinValue ? Age.ToString() : "")).Trim();
}
}
static void Main(string[] args)
{
var owner = new List<OT_Contact>
{
new OT_Contact("paul","p#o", 5),
new OT_Contact("paul","pppp#o"),
new OT_Contact("mani","kkk"),
new OT_Contact("olaf", "olaf", 22)
};
var borr = new List<OT_Contact>
{
new OT_Contact("paul","popel#o", 5),
new OT_Contact("paul","pppp#o"),
new OT_Contact("mani","kkk",99),
new OT_Contact("olaf", "", 22)
};
var trust = owner.Where(o => !borr.Any(b => b.Name == o.Name && b.Email == o.Email)).ToList();
System.Console.WriteLine("Owner:\n " + string.Join("\n ", owner));
System.Console.WriteLine("\nBorrower:\n " + string.Join("\n ", borr));
System.Console.WriteLine("\nTrustys:\n " + string.Join("\n ", trust));
System.Console.ReadLine();
}
}
Output (Age is not important for equality, hence not inside the Any-Clause):
Owner:
paul p#o 5
paul pppp#o
mani kkk
olaf olaf 22
Borrower:
paul popel#o 5
paul pppp#o
mani kkk 99
olaf 22
Trustys:
paul p#o 5
olaf olaf 22
This example models the IEnumerable.Except(..) used in the question. It will find any owner that is not found in the borrower list. The euqality-condition only takes Name and Email under consideration. If it finds an borrower with the same Name and Email it will not output him in the resulting list.
Any borrower that is only in the owner list won't make it into to the result either - getting any borrower that is not in owner could be accomplished by simply swapping the lists around:
var onlyBorr = borr.Where(b => !owner.Any(o => o.Name == b.Name && o.Email == b.Email)).ToList();
A feasable implementation of an IEqualityComparer for this contrieved example could be
public class OT_ContactEqualityComparer : IEqualityComparer<OT_Contact>
{
public bool Equals(OT_Contact x, OT_Contact y)
{
if (x == null || y == null)
return false;
return (x.Name == y.Name && x.Email == y.Email);
}
public int GetHashCode(OT_Contact c)
=> (c.Name ?? "").GetHashCode() ^ (c.Email ?? "").GetHashCode();
}
which would allow the usage of IEnumerable.Except like this:
System.Console.WriteLine("\nIEquality:\n " + string.Join("\n ",
owner.Except(borr, new OT_ContactEqualityComparer())));

Related

Compare two lists on one property and dont add duplicate

Hello so for some reason using various examples i havent been able to solve this.
So i have two lists one containing global values and one vlues that are set on a specific property. What i want to achieve is compare the two lists and keep the specific ones and then add the global ones that are not in the specific list based on its name.
i have tried this
var pidConfigValues = await _database.GetConfigurationValuesForPid(productGroup);
var globalConfigValues = await _database.GetGlobalConfigurationValues();
var allConfigs = pidConfigValues.Where(c => globalConfigValues.All(d => c.Name != d.Name)).ToList();
I guess something is wrong with the Where condition because the allConfigs ends up as empty. The both variables that gets compared are lists of same type of object
Example data
pidConfigValues would consist of objects like
Name: config.myConfig,
Pid: 2,
Value: 1
and globalConfigValues would be like
Name: config.myConfig,
Pid: Null,
Value: 0
Name: config.someOtherConfig,
Pid: Null,
Value: 1
So in the example above i would want allConfigs to be
Name: config.myConfig,
Pid: 2,
Value: 1
Name: config.someOtherConfig,
Pid: Null,
Value: 1
So in allConfigs only the config.myConfig with pid would be shown and from global only add the ones that does not exist in the specific one
Here is one way of doing it:
var pidConfigValues = new List<Config>()
{
new Config() { Name = "config.myConfig", Pid = 2, Value = 1}
};
var globalConfigValues = new List<Config>()
{
new Config() { Name = "config.myConfig", Pid = null, Value = 0},
new Config() { Name = "config.someOtherConfig", Pid = null, Value = 1}
};
var result = pidConfigValues.Concat(globalConfigValues)
.GroupBy(x => x.Name)
.Select(x => x.First()) //if multiple entities have the same name pick the first one which will be the one from pidConfigValues
One solution would be to use Union in combination with a custom EqualityComparer that compares the configs based on their Name-property:
// in your code:
var allConfigs = pidConfigValues.Union(globalConfigValues, new MyConfigComparer()).ToList();
// sample for the comparer:
public class MyConfigComparer : IEqualityComparer<MyConfig>
{
public bool Equals(MyConfig c1, MyConfig c2)
{
if (object.ReferenceEquals(c1, c2))
return true;
if (c1 == null || c2 == null)
return false;
return c1.Name.Equals(c2.Name, StringComparison.Ordinal);
}
public int GetHashCode(MyConfig x)
{
return x.Name.GetHashCode();
}
}
Ciao, you can use Distinct (by rewriting EqualityComparer). Here working example:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var pidConfigValues = new List<Configuration>();
var globalConfigValues = new List<Configuration>();
Configuration pidConfigValue = new Configuration("config.myConfig", 2, 1);
Configuration globalConfigValue1 = new Configuration("config.myConfig", null, 0);
Configuration globalConfigValue2 = new Configuration("config.someOtherConfig", null, 1);
globalConfigValues.Add(globalConfigValue1);
pidConfigValues.Add(pidConfigValue);
globalConfigValues.Add(globalConfigValue2);
List<Configuration> result = pidConfigValues.Concat(globalConfigValues)
.Distinct(new ConfigurationEqualityComparer()).ToList();
Console.WriteLine(String.Join(",", result));
Console.ReadLine();
}
}
public class Configuration
{
public string _name = "";
public Nullable<int> _pid = null;
public int _value = -1;
public Configuration(string name, Nullable<int> pid, int value)
{
this._name = name;
this._pid = pid;
this._value = value;
}
public override string ToString()
{
return "Name: " + this._name + " PID:" + this._pid + " Value:" + this._value + Environment.NewLine;
}
}
public class ConfigurationEqualityComparer
: EqualityComparer<Configuration>
{
public override bool Equals(Configuration c1, Configuration c2)
{
if (c1 == null && c2 == null)
return true;
else if (c1 == null || c2 == null)
return false;
else if (c1._name.Equals(c2._name))
{
if (c1._pid == null || c2._pid == null) return true;
else return false;
}
else
return false;
}
public override int GetHashCode(Configuration cnf)
{
int hCode = cnf._value ^ cnf._value;
return hCode.GetHashCode();
}
}
}
Explanation: Concat two lists and get only Distinct values. Equality comparer must be rewrited because we are using objects so we have to define which object is equal to another.
So your case is complicated to be solved by simple union or join operation. But simple enough to be solved by some simple select and concat operations.
What you need is to loop all loaded pidConfigValues and override a specific property with the global configuration, and then create a collection containing all unique configurations. Is that correct?
If so the solution could be like this:
var pidConfigValues = await _database.GetConfigurationValuesForPid(productGroup);
var globalConfigValues = await _database.GetGlobalConfigurationValues();
// loop through all pidConfigs and override their Pid value if matching global config exists
var allConfigs = pidConfigValues.Select(c =>
{
var matchingGlobalConfig = globalConfigValues.FirstOrDefault(g => g.Name == c.Name);
if (matchingGlobalConfig != null)
{
c.Pid = matchingGlobalConfig.Pid;
}
return c;
}).ToList();
// Find all global configs that are not matching any pidConfigValues
var productNames = pidConfigValues.Select(p => p.Name).ToArray();
var nonMatchingGlobalConfigs = globalConfigValues.Where(g => !productNames.Contains(g.Name)).ToArray();
// add non-matching global-configs to all-configs collection
allConfigs = allConfigs.Concat(nonMatchingGlobalConfigs).ToArray();

To Get Different values by comparing two objects in C#

I have two objects of the same class type and I want to fetch the different valued columns with values from both the objects.
I have tried the below code but I'm able to fetch only the column names.
public List<string> GetChangedProperties<T>(T a, T b) where T : class
{
if (a != null && b != null)
{
if (object.Equals(a, b))
{
return new List<string>();
}
var allProperties = a.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
return allProperties.Where(p => !object.Equals(p.GetValue(a), p.GetValue(b))).Select(p => p.Name).ToList();
}
else
{
var aText = $"{(a == null ? ("\"" + nameof(a) + "\"" + " was null") : "")}";
var bText = $"{(b == null ? ("\"" + nameof(b) + "\"" + " was null") : "")}";
var bothNull = !string.IsNullOrEmpty(aText) && !string.IsNullOrEmpty(bText);
throw new ArgumentNullException(aText + (bothNull ? ", " : "") + bText);
}
}
You can use a Dictionary instead of a List:
public class Program
{
static public Dictionary<string, Tuple<object, object>> GetChangedProperties<T>(T a, T b) where T : class
{
if ( a != null && b != null )
{
if ( Object.Equals(a, b) )
{
return new Dictionary<string, Tuple<object, object>>();
}
var allProperties = a.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
var result = new Dictionary<string, Tuple<object, object>>();
foreach ( var p in allProperties )
{
var v1 = p.GetValue(a);
var v2 = p.GetValue(b);
if ( !Object.Equals(v1, v2) )
result.Add(p.Name, new Tuple<object, object>(v1, v2));
}
return result;
}
else
{
var aText = $"{( a == null ? ( "\"" + nameof(a) + "\"" + " was null" ) : "" )}";
var bText = $"{( b == null ? ( "\"" + nameof(b) + "\"" + " was null" ) : "" )}";
var bothNull = !string.IsNullOrEmpty(aText) && !string.IsNullOrEmpty(bText);
throw new ArgumentNullException(aText + ( bothNull ? ", " : "" ) + bText);
}
}
public class Test
{
public int A { get; set; }
public int B { get; set; }
}
static void Main(string[] args)
{
var v1 = new Test { A = 10, B = 20 };
var v2 = new Test { A = 5, B = 20 };
var list = GetChangedProperties(v1, v2);
foreach ( var item in list )
Console.WriteLine($"{item.Key}: {item.Value.Item1.ToString()} != {item.Value.Item2.ToString()}");
Console.ReadKey();
}
}

Find next string in a list of string

I have a list of UserNames in a comma delimited string. I want to find next one of the input username.
For Example:
var s0 = "abc,deF,ghi,jkl";
var s1 = "abc";
var s2 = "def";
var s3 = "ghi";
var s4 = "jkl";
Result should be:
NextInString(s0,s1 ) == "def"
NextInString(s0,s2 ) == "ghi"
NextInString(s0,s3 ) == "jkl"
NextInString(s0,s4 ) == "jkl"
Here is what I have:
string NextInString(string listOfNames, string userName)
{
if(listOfNames == string.Empty || userName == string.Empty)
return string.Empty;
var s = listOfNames.Split(',');
var count = 0;
foreach (var element in s)
{
if (element == userName)break;
count++;
}
if (s.Length -1 == count)
{
return s[count];
}
else return s[ count + 1 ];
}
My question is, is there a better/easier way to approach this?
If you take the extra step to ensure your string list is trimmed, you can just use the IndexOf() method of List<T>:
string csv = "test1, test2, test3, test4";
List<string> names = csv.Split(',').Select(x => x.Trim()).ToList();
Then your NextInString() method (I think this is a poorly named method) would look like this:
private static string NextInString(List<string> names, string userName)
{
int index = names.IndexOf(userName);
if(names.Count - 1 == index || index == -1)
{
return "No result";
}
else
{
return names[index + 1];
}
}
I made a fiddle here
You can use Linq like this:
string userName = "abc";
string listOfNames = "abc,xyz,123";
var names = listOfNames
.Split(',')
.Select((n, i) => new {name = n, index =i} )
.ToArray();
var firstMatch = names.FirstOrDefault(n => n.name == userName);
var result = firstMatch == null
? string.Empty
: firstMatch.index == names.Length - 1
? string.Empty
: names[firstMatch.index + 1].name;
Here is the LINQ approach:
string NextInString(string listOfNames, string userName)
{
if(listOfNames == string.Empty || userName == string.Empty) return string.Empty;
var names = listOfNames.Split(',');
return names
.SkipWhile(x => x != userName)
.Skip(1)
.FirstOrDefault() ?? names.Last();
}
You can make a nice little extension method to do this after the string is split, like so:
static class IListExtensions
{
public static T FindItemAfter<T>(this IList<T> list, T targetItem)
{
return list[list.IndexOf(targetItem)+ 1];
}
}
You can use it like this:
static void Main(string[] args)
{
var list = "cat,dog,rat".Split(',');
Console.WriteLine(list.FindItemAfter("cat"));
Console.WriteLine(list.FindItemAfter("dog"));
Console.ReadLine();
}
It returns:
dog
rat
This overload will allow you to specify a default value that gets returned if the requested item isn't found, or the next item would be outside the list.
public static T FindItemAfter<T>(this IList<T> list, T targetItem, T defaultValue)
{
var index = list.IndexOf(targetItem);
if (index == -1 || index >= list.Count - 1)
{
return defaultValue;
}
return list[index + 1];
}
How about something like this?
var s = listOfNames.Split(',');
for (var i = 0; i < s.count; i++)
{
if (i == s.count - 1)
{
return string.Format("No user after {0} was found", userName);
}
else if (s[i] == userName)
{
return s[i + 1];
}
}

Icomparer c# List

I have a list of image name like this {"1.jpg", "10.jpg", "2.jpg"}.
I would like to sort like this {"1.jpg", "2.jpg", "10.jpg"}.
I created this comparer. That means if x or y == "DSC_10.jpg", so if list is {"DSC_1.jpg", "DSC_10.jpg", "DSC_2.jpg", ...} don't sort and keep the list.
var comparer = new CompareImageName();
imageUrls.Sort(comparer);
return imageUrls;
public class CompareImageName : IComparer<string>
{
public int Compare(string x, string y)
{
if (x == null || y == null) return 0;
var l = x.Split('/');
var l1 = y.Split('/');
int a, b;
var rs = int.TryParse(l[l.Length - 1].Split('.')[0], out a);
var rs2 = int.TryParse(l1[l1.Length - 1].Split('.')[0], out b);
if (!rs || !rs2) return 0;
if (a == b || a == 0 && b == 0) return 0;
return a > b ? 1 : -1;
}
}
This sort correctly with name {"1.jpg", "10.jpg", "2.jpg"}, but incorrectly if list is {"DSC_1.jpg", "DSC_10.jpg", "DSC_2.jpg", ...}.
I read in MSDN:
What wrong with my code?
I think you're better off doing a bit of Regex for this. Try this solution:
public class CompareImageName : IComparer<string>
{
public int Compare(string x, string y)
{
if (x == null || y == null) return 0;
var regex = new Regex(#"/(((?<prefix>\w*)_)|)((?<number>\d+))\.jpg$");
var mx = regex.Match(x);
var my = regex.Match(y);
var r = mx.Groups["prefix"].Value.CompareTo(my.Groups["prefix"].Value);
if (r == 0)
{
r = int.Parse(mx.Groups["number"].Value).CompareTo(int.Parse(my.Groups["number"].Value));
}
return r;
}
}
Apart from the Regex string itself this is easier to follow the logic.
Here is your solution check this example, following class will do the comparison
public class NumericCompare : IComparer<string>
{
public int Compare(string x, string y)
{
int input1,input2;
input1=int.Parse(x.Substring(x.IndexOf('_')+1).Split('.')[0]);
input2= int.Parse(y.Substring(y.IndexOf('_')+1).Split('.')[0]);
return Comparer<int>.Default.Compare(input1,input2);
}
}
You can make use of this class like the following:
var imageUrls = new List<string>() { "DSC_1.jpg", "DSC_10.jpg", "DSC_2.jpg" };
var comparer = new NumericCompare();
imageUrls.Sort(comparer);
Console.WriteLine(String.Join("\n",imageUrls));
Try this with simple OrderBy
var SortedList = imageUrls.OrderBy(
x=>int.Parse(
x.Substring(x.IndexOf('_')+1).Split('.')[0])
).ToList();
Basically what you want to do is sort by the numeric part within the string. You are almost there. You just have to handle the part when you split a case like this DSC_2.jpg using a . then the first part is not all digits. So you need to get digits and then compare those. Here is the code. Please note I have made the assumption you will have backslash and if that is not the case then please handle it:
public int Compare(string x, string y)
{
if (x == null || y == null) return 0;
var nameX = x.Substring(x.LastIndexOf('/'));
var nameY = y.Substring(y.LastIndexOf('/'));
var nameXParts = nameX.Split('.');
var nameYParts = nameY.Split('.');
int a, b;
var rs = int.TryParse(nameXParts[0], out a);
var rs2 = int.TryParse(nameYParts[0], out b);
var nameXDigits = string.Empty;
if (!rs)
{
for (int i = 0; i < nameXParts[0].Length; i++)
{
if (Char.IsDigit(nameXParts[0][i]))
nameXDigits += nameXParts[0][i];
}
}
var nameYDigits = string.Empty;
if (!rs2)
{
for (int i = 0; i < nameYParts[0].Length; i++)
{
if (Char.IsDigit(nameYParts[0][i]))
nameYDigits += nameYParts[0][i];
}
}
int.TryParse(nameXDigits, out a);
int.TryParse(nameYDigits, out b);
if (a == b || a == 0 && b == 0) return 0;
return a > b ? 1 : -1;
}
Don't use imageUrls.Sort(comparer); on List because it doesn't accept 0 value as keeping the order of elements.
Reason:
The Sort performs an unstable sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal.
Link: https://msdn.microsoft.com/en-gb/library/w56d4y5z.aspx
Solution: Let's try to use OrderBy with your compare
var imageUrls1 = new List<string>() { "1.jpg", "10.jpg", "2.jpg" };
var imageUrls2 = new List<string>() { "DSC_1.jpg", "DSC_10.jpg", "DSC_2.jpg" };
var comparer = new CompareImageName();
//Sort normally
imageUrls1 = imageUrls1.OrderBy(p=>p, comparer).ToList();
//Keep the order as your expectation
imageUrls2 = imageUrls2.OrderBy(p=>p, comparer).ToList();
Maybe you can try doing this in a function instead of writing a comparator. I can't think of a good way to implement this logic as a comparator since there are different rules based on the contents (don't sort if the file name is not numeric).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace sortinglists
{
public class MainProgram
{
public static void Main()
{
var imageUrlsNumbers = new List<string>();
imageUrlsNumbers.Add("c:/a/b/1.jpg");
imageUrlsNumbers.Add("c:/a/b/10.jpg");
imageUrlsNumbers.Add("c:/a/b/2.jpg");
CustomSort(ref imageUrlsNumbers);
foreach (var imageUrl in imageUrlsNumbers)
{
Console.WriteLine(imageUrl);
}
var imageUrlsText = new List<string>();
imageUrlsText.Add("c:/a/b/DSC_1.jpg");
imageUrlsText.Add("c:/a/b/DSC_10.jpg");
imageUrlsText.Add("c:/a/b/DSC_2.jpg");
CustomSort(ref imageUrlsText);
foreach (var imageUrl in imageUrlsText)
{
Console.WriteLine(imageUrl);
}
}
public static void CustomSort(ref List<string> imageUrls)
{
if (imageUrls
.Select(s => s.Substring(s.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1))
.Select(t => t.Substring(0, t.IndexOf(".", StringComparison.OrdinalIgnoreCase)))
.Where(u => new Regex("[A-Za-z_]").Match(u).Success)
.Any())
{
imageUrls = imageUrls
.Select(x => x.Substring(x.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1))
.ToList();
}
else
{
imageUrls = imageUrls
.Select(v => v.Substring(v.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1))
.OrderBy(w => Convert.ToInt32(w.Substring(0, w.LastIndexOf(".", StringComparison.OrdinalIgnoreCase))))
.ToList();
}
}
}
}
The output for imageUrlsNumbers after sorting is:
1.jpg
2.jpg
10.jpg
And the output for imageUrlsText after sorting is:
DSC_1.jpg
DSC_10.jpg
DSC_2.jpg

Reflection help. Make a collection from a class based on its properties?

I need a little help. I am fairly new to reflection. We're using a 3rd party api and it returns a class called "AddressList". It has public properties within it literally called Address1, Address1Name, Address1Desc, Address2, Address2Name, Address2Desc, Address3, Address3Name, Address3Desc,... Address99, Address99Name, Address99Desc.. There are also a couple of other properties. I have a class called "SimpleAddress" that has just the 3 properties (Address, Name, Description). What I want to do is when I get the "AddressList" class returned, I would like to loop AddressDesc1... through AddressDesc99... and whichever ones are not null or empty, I would like to create an instance of "SimpleAddress", populate it's properties, and add it to a List... Can someone point me in the right direction? Obviously this would have been better if "AddressList" was some sort of collection, but unfortunately it is not. It is generated from a return string from a mainframe.
Thanks for any help,
~ck in San Diego
Ick. You could do something like this:
List<SimpleAddress> addresses = new List<SimpleAddress>();
string addressPropertyPattern = "Address{0}";
string namePropertyPattern = "Address{0}Name";
string descPropertyPattern = "Address{0}Desc";
for(int i = 1; i <= MAX_ADDRESS_NUMBER; i++)
{
System.Reflection.PropertyInfo addressProperty = typeof(AddressList).GetProperty(string.Format(addressPropertyPattern, i));
System.Reflection.PropertyInfo nameProperty = typeof(AddressList).GetProperty(string.Format(namePropertyPattern, i));
System.Reflection.PropertyInfo descProperty = typeof(AddressList).GetProperty(string.Format(descPropertyPattern, i));
SimpleAddress address = new SimpleAddress();
address.Address = (string)addressProperty.GetValue(yourAddressListObject, null);
address.Name = (string)nameProperty.GetValue(yourAddressListObject, null);
address.Description = (string)descProperty.GetValue(yourAddressListObject, null);
addresses.Add(address);
}
Start by getting the type of the class in question and invoke the GetProperties method.
PropertyInfo[] properties = myMainframeObject.GetType().GetProperties();
Each PropertyInfo has a Name attribute (a string) you can use to match against. Loop over all the properties, and write the code that creates a new instance of SimpleAddress.
Inside this loop, you can access your mainframe object and pull out the property values you need:
// imagine that in this case, 'p' is a PropertyInfo that represents Address2Name
var simpleAddress = new SimpleAddress();
simpleAddress.Name = p.GetValue(myMainframeObject, null);
(the null is never used for normal properties - it is intended for use with indexed properties).
You should be able to do something like:
List<SimpleAddress> CreateList(AddressList address)
{
List<SimpleAddress> values = new List<SimpleAddress>();
Type type = address.GetType();
for (int i=1;i<=99;++i)
{
string address = type.GetProperty("Address" + i.ToString()).GetValue(address,null).ToString();
string addressDesc = type.GetProperty("Address" + i.ToString() + "Desc").GetValue(address,null).ToString();
string addressName = type.GetProperty("Address" + i.ToString() + "Name").GetValue(address,null).ToString();
if (!string.IsNullOrEmpty(addressDesc) || !string.IsNullOrEmpty(addressName) || !string.IsNullOrEmpty(address) )
value.Add(new SimpleAddress(address,addressDesc,addressName));
}
return values;
}
Not tested (for obvious reasons), but something like:
List<SimpleAddress> newList = new List<SimpleAddress>();
AddressList list = ...
Type type = list.GetType();
PropertyInfo prop1, prop2, prop3;
int index = 1;
while((prop1 = type.GetProperty("Address" + index)) != null
&& (prop2 = type.GetProperty("Address" + index + "Name")) != null
&& (prop3 = type.GetProperty("Address" + index + "Desc")) != null) {
string addr = (string) prop1.GetValue(list, null),
name = (string) prop2.GetValue(list, null),
desc = (string) prop3.GetValue(list, null);
if(addr == null || name == null || desc == null) {
continue; // skip but continue
}
SimpleAddress newAddr = new SimpleAddress(addr, name, desc);
newList.Add(newAddr);
index++;
}
if you want to use linq
public static class MyTools
{
public static TReturn GetValue<TReturn>(this object input,
string propertyName)
{
if (input == null)
return default(TReturn);
var pi = input.GetType().GetProperty(propertyName);
if (pi == null)
return default(TReturn);
var val = pi.GetValue(input, null);
return (TReturn)(val == null ? default(TReturn) : val);
}
public static string GetString(this object input, string propertyName)
{
return input.GetValue<string>(propertyName);
}
public static List<SimpleAddress> GetAddress(this MyObject input)
{
return (
from i in Enumerable.Range(1, 2)
let address = input.GetString("Address" + i.ToString())
let name = input.GetString("Address" + i.ToString() + "Name")
let desc = input.GetString("Address" + i.ToString() + "Desc")
select new SimpleAddress() { Address = address,
Name = name,
Description = desc }
).ToList();
}
}
var addrList = new AddressList
{
Address1Name = "ABC",
Address1Desc = "DEF",
Address1 = "GHI",
Address3Name = "X",
Address3Desc = "Y",
Address3 = "Z"
};
var addresses =
from i in Enumerable.Range(1, 99)
let desc = typeof(AddressList).GetProperty(string.Format("Address{0}Desc", i)).GetValue(addrList, null) as string
let name = typeof(AddressList).GetProperty(string.Format("Address{0}Name", i)).GetValue(addrList, null) as string
let address = typeof(AddressList).GetProperty(string.Format("Address{0}", i)).GetValue(addrList, null) as string
where !string.IsNullOrEmpty(address)
select new SimpleAddress
{
Name = name,
Description = desc,
Address = address
};

Categories