Combine two list values into one - c#

is there a way to combine these to list items into one list item ? i am sorry if this is a begginer mistake
List<string> values = new List<string>();
foreach (Feature f in allFeatures)
{
if (f.ColumnValues.ContainsKey(layercode)&& f.ColumnValues.ContainsKey(layercode2))
{
if (!values.Contains(f.ColumnValues[layercode].ToString()) && !values.Contains(f.ColumnValues[layercode2].ToString()))
{
values.Add(f.ColumnValues[layercode].ToString());
values.Add(f.ColumnValues[layercode2].ToString());
}
}
}

You can use a List of Tuples, a Dictionary, or create a class. I will not go into depth explaining these as you should be able to easily search and find other questions all about these. Some of this is from memory so syntax might be a bit off.
List of Tuples
List<Tuple<string,string>> values = new List<Tuple<string,string>>();
//...
if ( !values.Any(v=>v.Item1 == f.ColumnValues[layercode].ToString()) && !values.Any(v=>v.Item2 == f.ColumnValues[layercode2].ToString()) )
{
values.Add( Tuple.Create(f.ColumnValues[layercode].ToString(),
f.ColumnValues[layercode2].ToString()) );
}
Dictionary
Dictionary<string,string> values = new Dictionary<string,string> ();
//...
if (!values.ContainsKey(f.ColumnValues[layercode].ToString()) && !values.ContainsValue(f.ColumnValues[layercode2].ToString()))
{
values[f.ColumnValues[layercode].ToString()] = f.ColumnValues[layercode2].ToString();
}
List of class instances
public class LayerCodePair {
public string Code1 {get;set;}
public string Code2 {get;set;}
} // declared outside of method
...
List<LayerCodePair> values = new List<LayerCodePair>();
//...
if (!values.Any(v=> v.Code1 == f.ColumnValues[layercode].ToString()) && !values.Any(v=>v.Code2 == f.ColumnValues[layercode2].ToString()))
{
values.Add(new LayerCodePair{
Code1 = f.ColumnValues[layercode].ToString(),
Code2 = f.ColumnValues[layercode2].ToString()
});
}

It should work for you, using ";" character as a separator:
List<string> values = new List<string>();
foreach (Feature f in allFeatures)
{
var columnValues = f.ColumnValues;
var firstLayerCode = columnValues[layercode].ToString();
var secondLayerCode = columnValues[layercode2].ToString();
if (columnValues.ContainsKey(layercode) && columnValues.ContainsKey(layercode2))
{
if (!values.Contains(firstLayerCode) && !values.Contains(secondLayerCode))
{
var combinedValue = firstLayerCode + ";" + secondLayerCode;
values.Add(combinedValue);
}
}
}

Related

Linq select Objects from List which have empty String

is it possible in Linq to select from IEnumerable of this object
public class Foo
{
public int Id { get; set; }
public string Type { get; set; }
}
where Type is "" ?
if I loop over the list with that
foreach (Foo f in dataFoos)
{
Console.WriteLine(f.Id + f.Type);
}
it looks like
1one
2
3three
I have tried
var emptyType0 = dataFoos.Where(f => f.Type.Length <= 1);
var emptyType1 = dataFoos.Where(f => f.Type == null || f.Type == "");
both did not return any result. Any hint on how to properly check if String values are empty ?
if I do that
var df = dataFoos.Where(f => String.IsNullOrWhiteSpace(f.Type));
foreach (Foo f in df)
{
Console.WriteLine(f.Id + f.Type);
}
var df1 = dataFoos.Where(f => !String.IsNullOrWhiteSpace(f.Type));
foreach (Foo f in df1)
{
Console.WriteLine(f.Id + f.Type);
}
the second loop does not return any value
I am using dotnetcore c#. Thanks for any hint
This should cover almost every type of null/blank/just whitespace
var emptyType1 = foos.Where(f => String.IsNullOrWhiteSpace(f.Type));
but more likely what you want to do is exclude those - not include them
var dataFoos = foos.Where(f => !String.IsNullOrWhiteSpace(f.Type));
foreach (Foo f in dataFoos)
{
Console.WriteLine(f.Id + f.Type);
}

Get string from another string array if value matches

String Array 1: (In this format: <MENU>|<Not Served?>|<Alternate item served>)
Burger|True|Sandwich
Pizza|True|Hot Dog
String Array 2: (Contains Menu)
Burger
Pizza
Grill Chicken
Pasta
I need the menu is served or any alternate item served for that particular item.
Code:
for(int i = 0; i < strArr2.Length; i++)
{
if(strArr2.Any(_r => _r.Split('|').Any(_rS => _rS.Contains(strArr1[i]))))
{
var menu = strArr2[i];
var alternate = ? // need to get alternate item
}
}
As I commented in the code, how to get the alternate item in that string array? Please help, thanks in advance.
P.S: Any help to trim if condition is also gladly welcome.
Instead of any, you may use Where to get the value matching.
#Markus is having the detailed answer, I am just using your code to find a quick fix for you.
for(int i = 0; i < strArr2.Length; i++)
{
if(strArr2.Any(_r => _r.Split('|').Any(_rS => _rS.Contains(strArr1[i]))))
{
var menu = strArr2[i];
var alternate = strArr2.Where(_rs => _rs.Split('|').Any(_rS => _rS.Contains(strArr1[i]))).First().Split('|').Last();
}
}
In order to simplify your code, it is a good idea to better separate the tasks. For instance, it will be much easier to handle the contents of string array 1 after you have converted the contents into objects, e.g.
class NotServedMenu
{
public string Menu { get; set; }
public bool NotServed { get; set; }
public string AlternateMenu { get; set; }
}
Instead of having an array of strings, you can read the strings to a list first:
private IEnumerable<NotServedMenu> NotServedMenusFromStrings(IEnumerable<string> strings)
{
return (from x in strings select ParseNotServedMenuFromString(x)).ToArray();
}
private NotServedMenu ParseNotServedMenuFromString(string str)
{
var parts = str.Split('|');
// Validate
if (parts.Length != 3)
throw new ArgumentException(string.Format("Unable to parse \"{0}\" to an object of type {1}", str, typeof(NotServedMenu).FullName));
bool notServedVal;
if (!bool.TryParse(parts[1], out notServedVal))
throw new ArgumentException(string.Format("Unable to read bool value from \"{0}\" in string \"{1}\".", parts[1], str));
// Create object
return new NotServedMenu() { Menu = parts[0],
NotServed = notServedVal,
AlternateMenu = parts[2] };
}
Once you can use the objects, the subsequent code will be much cleaner to read:
var notServedMenusStr = new[]
{
"Burger|True|Sandwich",
"Pizza|True|Hot Dog"
};
var notServedMenus = NotServedMenusFromStrings(notServedMenusStr);
var menus = new[]
{
"Burger",
"Pizza",
"Grill Chicken",
"Pasta"
};
var alternateMenus = (from m in menus join n in notServedMenus on m equals n.Menu select n);
foreach(var m in alternateMenus)
Console.WriteLine("{0}, {1}, {2}", m.Menu, m.NotServed, m.AlternateMenu);
In this sample, I've used a Linq join to find the matching items.
You could do something like that
string[] strArr1 = { "Burger|True|Sandwich", "Pizza|True|Hot Dog" };
string[] strArr2 = { "Burger", "Pizza", "Grill Chicken", "Pasta" };
foreach (string str2 in strArr2)
{
string str1 = strArr1.FirstOrDefault(str => str.Contains(str2));
if (str1 != null)
{
string[] splited = str1.Split('|');
string first = splited[0];
bool condition = Convert.ToBoolean(splited[1]);
string second = splited[2];
}
}

Remove 'duplicates' from a list of pairings

Title could be misleading, so an example:
I have a class:
class Pair
{
Book Book1;
Book Book2;
}
I have a list of these:
var list = new List<Pair>();
list.Add(new Pair() {
Book1 = new Book() { Id = 123 },
Book2 = new Book() { Id = 456 }
});
list.Add(new Pair() {
Book1 = new Book() { Id = 456 },
Book2 = new Book() { Id = 123 }
});
Now, despite the fact the books are 'flipped', my system should treat these as duplicates.
I need a method to remove one of these 'duplicates' from the list (any one - so let's say the first to make it simple).
What I've Tried
var tempList = new List<Pair>();
tempList.AddRange(pairs);
foreach (var dup in pairs)
{
var toRemove = pairs.FirstOrDefault(o => o.Book1.Id == dup.Book2.Id
&& o.Book2.Id == dup.Book1.Id);
if (toRemove != null)
tempList.Remove(toRemove);
}
return tempList;
This returns no items (given the example above), as both Pair objects would satisfy the condition in the lambda, I only one to remove one though.
NOTE: This wouldn't happen if I just removed the element from the collection straight away (rather than from a temporary list) - but then I wouldn't be able to iterate over it without exceptions.
You can set up an IEqualityComparer<Pair> concrete class and pass that to the .Distinct() method:
class PairComparer : IEqualityComparer<Pair>
{
public bool Equals(Pair x, Pair y)
{
return (x.Book1.Id == y.Book1.Id && x.Book2.Id == y.Book2.Id)
|| (x.Book1.Id == y.Book2.Id && x.Book2.Id == y.Book1.Id);
}
public int GetHashCode(Pair obj)
{
return obj.Book1.Id.GetHashCode() ^ obj.Book2.Id.GetHashCode();
}
}
And then use it like so:
var distinctPairs = list.Distinct(new PairComparer());
The problem is that you are removing the both duplicates.
Try this:
var uniquePairs = list.ToLookup( p => Tuple.Create(Math.Min(p.Book1.Id, p.Book2.Id), Math.Max(p.Book1.Id, p.Book2.Id)) ).Select( g => g.First() ).ToList();
I would use the following
foreach (var dup in pairs)
{
var toRemove = pairs.FirstOrDefault(o => o.Book1.Id == dup.Book2.Id
&& o.Book2.Id == dup.Book1.Id
&& o.Book1.Id > o.Book2.Id);
if (toRemove != null)
tempList.Remove(toRemove);
}
This will specifically remove the duplicate that is "out of order". But this (and your original) will fail if the duplicate pairs have the books in the same order.
A better solution (since we're looping over ever pair anyways) would be to use a HashSet
var hashSet = new HashSet<Tuple<int,int>>();
foreach (var item in pairs)
{
var tuple = new Tuple<int,int>();
if (item.Book1.Id < item.Book2.Id)
{
tuple.Item1 = item.Book1.Id;
tuple.Item2 = item.Book2.Id;
}
else
{
tuple.Item1 = item.Book2.Id;
tuple.Item2 = item.Book1.Id;
}
if (hashSet.Contains(tuple))
{
tempList.Remove(dup);
}
else
{
hashSet.Add(tuple);
}
}
I've managed to find a solution, but it's one I'm not happy with. It seems too verbose for the job I'm trying to do. I'm now doing an additional check to see whether a duplicate has already been added to the list:
if(toRemove != null && tempList.Any(o => o.Book1.Id == toRemove.Book2.Id
&& o.Book2.Id == toRemove.Book1.Id))
tempList.Remove(toRemove);
I'm very much open to alternative suggestions.

Convert custom delimited string to List<myClass>?

How do I turn this:
string x = "key:value|key:value|key:value|key:value";
into this?
List<myClass> listObj;
myClass definition:
public class myClass
{
public string keyName { get; set; }
public string keyValue { get; set; }
}
There has to be a way to do it using LINQ or something :)
thanks in advance!
* NOTE *
I should add I know how to do this splitting it and looping through it, but there has to be a better way :)
This will require separate ToList() call, but I like query syntax for its declarative nature:
from s in x.Split('|')
let parts = s.Split(':')
select new myClass {
keyName = parts[0],
keyValue = parts[1]
}
Or you can use fluent syntax:
x.Split('|')
.Select(s => {
var parts = s.Split(':');
return new myClass {
keyName = parts[0],
keyValue = parts[1]
};
}).ToList()
Well, since you really wanted to avoid splitting and looping...
public List<MyClass> Parse(string base, string workingName, string workingValue,
bool processingName = true,
List<MyClass> workingList = null, int index = 0)
{
if (workingList == null)
workingList = new List<MyClass>();
if (index >= base.Length)
{
return workingList;
}
if (base[index] = '|')
{
workingList.Add(new MyClass { keyName = workingName, keyValue = workingValue });
return Parse(base, "", "", true, workingList, index + 1);
}
else if (base[index] = ':')
{
return Parse(base, workingName, "", false, workingList, index + 1);
}
else if (processingName)
{
return Parse(base, workingName + base[index], "", processingName, workingList, index + 1);
}
else
{
return Parse(base, workingName, workingValue + base[index], processingName, workingList, index + 1);
}
}
But please, for the love of whatever you hold dear, don't do anything even remotely resembling that (and yes, this is untested, hand-written code, so there are probably errors - just making a joke about avoiding things).
Do this if you prefer to use your custom class instead of Dictionary
var result = from y in x.Split('|')
let obj = y.Split(':')
select new myClass{keyName = obj[0], keyValue = obj[1]};
var list = result.ToList();

Searching a nested List<T>

I have this data structure:
class Conference
{
private List<List<string>>_orgs;
public List<List<string>> Orgs
{
set { _orgs = value; } get { return _orgs; }
}
}
Data in this collection:
List<string> sublist = new List<string>();
sublist.Add("university");
sublist.Add("organization");
List<List<string>> list = new List<List<string>>();
list.Add(sublist);
Then:
Conference c = new Conference();
c.Orgs = list;
I have collection of conference objects:
List<Conference> listConferences = new List<Conference>();
listConferences.Add(c);
I want search a string like "uni" and find collection of conference have orgs like "uni". How can I do this?
You can do this:
var selection = listConferences
.Where(x => x.Orgs.SelectMany(y => y).Any(y => y.Contains("uni")))
.ToList();
Note:
the trailing ToList() might not be necessary depending on your needs (e.g. if you iterate selection only once you can skip it).
Please use this code, below;
instead of third one, you may use your own conference list. you can now use similar to like keyword.
List<string> first = new List<string>();
first.Add("University");
first.Add("Standard");
List<List<string>> second = new List<List<string>>();
second.Add(first);
List<List<List<string>>> third = new List<List<List<string>>>();
third.Add(second);
var e = third.Find(delegate(List<List<string>> r)
{
bool isValid = false;
if(r.Count > 0)
{
foreach(List<string> s in r)
{
if(s.Count > 0 )
{
isValid = s.FindAll(delegate(string t){ return t.StartsWith("uni", StringComparison.OrdinalIgnoreCase);}).Count > 0;
}
}
}
return isValid;
});
Done, one more workout using linq. You should be feeling comfortable with this:
var univ = from p in c.Orgs
select p.FindAll(r => r.FindAll(s => s.StartsWith("univ", StringComparison.OrdinalIgnoreCase)));

Categories

Resources