Below is the code:
string[] values = Acode.Split(',');
IEnumerable<Test> tst = null;
foreach (string a in values)
{
if (tst== null)
tst = entities.Test.Where(t=> (t.TCode == Convert.ToInt16(a)));
else
tst.Concat(entities.Test.Where(g => (g.TCode == Convert.ToInt16(a))));
}
return tst.ToList();
I am not able to get all the records in tst, it is giving me records only for the last value in array.
So if my array contains 1,2,3,4 I am getting records only for the 4. Whereas i need all the result for 1,2,3 and 4 get appended in tst.
Any help will be appreciated.
Concat doesn't modify anything - it returns a new sequence, which you're currently ignoring.
However, rather than using Concat, you should just use SelectMany to flatten the sequence:
string[] values = Acode.Split(',');
return values.SelectMany(a => entities.Test.Where(t => t.TCode == Convert.ToInt16(a)))
.ToList();
Or more efficiently, convert values into a List<short> and then you can do one query:
List<short> values = Acode.Split(',').Select(x => short.Parse(x)).ToList();
return entities.Test.Where(t => values.Contains(t.TCode)).ToList();
That is because Concat will return a new instance of your enumerable.
Either use in your else :
tst = tst.Concat(...)
Or Change your Enumerable into list from the beginning :
string[] values = Acode.Split(',');
List<Test> tst= new List<Test>;
foreach (string a in values)
{
tst.AddRange(entities.Test.Where(g => (g.TCode == Convert.ToInt16(a))));
}
return tst;
Related
I have a list of objects I want to reorder. The order is determined in a string.
(I hope my current code explains better than the text)
List<DataObject> objects = GetDataObjectsFromDatabase();
string order = "1,3,2";
List<DataObject> orderedObjects = new List<DataObject>
foreach(string index in order.Split(',')
{
orderedObjects.Add(objects.FirstOrDefault(x => x.id == index));
}
Is there a single Linq statement or a better way to do this?
Here is example of ordering list based on another list in linq:
List<OBJ> Test = new List<OBJ>();
Test.Add(new OBJ(1));
Test.Add(new OBJ(2));
string Order = "1,2,3";
List<string> OrderBy = Order.Split(new char[] { ',' }).ToList();
Test = Test.OrderBy(x => OrderBy.IndexOf(x.Field1.ToString())).ToList();
Console.ReadKey();
Assuming that x.Field1 is your ID (or whatever field you want to sort by).
Provided that .Select() will happen in order:
var orderedObjects = order.Split(',').Select(int.Parse).Select(index => objects.FirstOrDefault(obj => obj.id == index).ToList();
var data = order.Split(',').ToList();
Let's say I have a list of strings:
originalList = { "XX.one", "XX.two", "YY.three" }
I want to use linq to select and return a list with {"one", "two"}.
if I do for example
resultList = originalList.FindAll(o => o.StartsWith("XX")));
I will get resultList = { "XX.one", "XX.two" } but what I want is resultList = { "one", "two" }
Any way to solve this?
EDIT: Thanks for all who answered, I've chosen the split function of #er-mfahhgk since it does the minimum of manipulation and doesn't depend on size of the prefix.
You can use SelectWith your desired string and then using Split function on Dot (.) you can select the second part like
var resultList = originalList.Where(o => o.StartsWith("XX"))
.Select(x => x.Split('.')[1])
.ToList();
And finally your output will be,
foreach (var item in resultList)
{
Console.WriteLine(item);
}
Console.ReadLine();
Output:
result = originalList.Where(o => o.StartsWith("XX"))
.Select(x=>x.Replace("XX.,""))
.ToList();
You could try this:
resultList = originalList.Where(o => o.StartsWith("XX"))
.Select(x=>x.Substring(3))
.ToList();
( edited to correct wording of Substring )
So I've got the following code:
string matchingName = "Bob";
List<string> names = GetAllNames();
if (names.Contains(matchingName))
// Get the index/position in the list of names where Bob exists
Is it possible to do this with a couple of lines of code, rather than iterating through the list to get the index or position?
If you have multiple matching instances and want to get all the indices you can use this:
var result = Enumerable.Range(0, names.Count).Where(i => names[i] == matchingName);
If it is just one index you want, then this will work:
int result = names.IndexOf(matchingName);
If there is no matching instance in names, the former solution will yield an empty enumeration, while the latter will give -1.
var index = names.IndexOf(matchingName);
if (index != -1)
{
// do something with index
}
If you want to look for a single match, then IndexOf will suit your purposes.
If you want to look for multiple matches, consider:
var names = new List<string> {"Bob", "Sally", "Hello", "Bob"};
var bobIndexes = names.Select((value, index) => new {value, index})
.Where(z => z.value == "Bob")
.Select(z => z.index);
Console.WriteLine(string.Join(",", bobIndexes)); // this outputs 0,3
The use of (value, index) within Select gives you access to both the element and its index.
I have a Class named Privilegeswith the following properties int UserId,string FormName,string CompName,int Privilege
And I have 2 lists of Privileges type with different values as the sample below
List<Privileges> list1 = new List<Privileges>(){
new Privileges(){UserId= 1,FormName="Form1",CompName="Button1",Privilege=2},
new Privileges(){UserId= 2,FormName="Form1",CompName="Button3",Privilege=3},
new Privileges(){UserId= 3,FormName="Form2",CompName="Button2",Privilege=2}
};
List<Privileges> list2 = new List<Privileges>(){
new Privileges(){UserId= 5,FormName="Form1",CompName="Button1",Privilege=2},
new Privileges(){UserId= 2,FormName="Form1",CompName="Button3",Privilege=4},
new Privileges(){UserId= 4,FormName="Form2",CompName="Button2",Privilege=3}
};
I want to make 3 functions
I made the first one which returns matched elements between the 2 lists
and the result is the following
{UserId= 2,FormName="Form1",CompName="Button3",Privilege=3}
The 2nd function should return elements that exist in the first list and not in the second list, with the following result
{UserId= 1,FormName="Form1",CompName="Button1",Privilege=2},
{UserId= 3,FormName="Form2",CompName="Button2",Privilege=2}
The 3rd function should return elements that exist in the second list and not in the first list, with the following result
{UserId= 5,FormName="Form1",CompName="Button1",Privilege=2},
{UserId= 4,FormName="Form2",CompName="Button2",Privilege=3}
The matching clause should compare UserId,FormName,CompName values regardless what the value of privilege is.
you can check my code snippet here
You don't have to write any complex LINQ statements for these (and many more) tasks. Just define an IEqualityComparer and everything becomes almost ridiculously simple:
class PrivilegesComparer : IEqualityComparer<Privileges>
{
public bool Equals(Privileges x, Privileges y)
{
return x.UserId == y.UserId
&& x.FormName == y.FormName
&& x.CompName == y.CompName;
}
public int GetHashCode(Privileges obj)
{
return (obj.UserId + obj.FormName + obj.CompName).GetHashCode();
}
}
Usage:
var comparer = new PrivilegesComparer();
var intersect = list1.Intersect(list2, comparer);
var l1Exceptl2 = list1.Except(list2, comparer);
var l2Exceptl1 = list2.Except(list1, comparer);
Which represent your first, second and third function, respectively.
That's quite different from writing a complex LINQ statement for each individual task.
Elements in list1 not in list2
var itemsInList1NotInList2 = list1.Where(l1 => !list2.Any(l2 => l1.UserId == l2.UserId && l1.FormName == l2.FormName && l1.CompName == l2.CompName)).ToList();
Elements in list2 not in list1
var itemsInList2NotInList1 = list2.Where(l2 => !list1.Any(l1 => l1.UserId == l2.UserId && l1.FormName == l2.FormName && l1.CompName == l2.CompName)).ToList();
I have two lists:
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
I want do to something like
var newData = data1.intersect(data2, lambda expression);
The lambda expression should return true if data1[index].ToString() == data2[index]
You need to first transform data1, in your case by calling ToString() on each element.
Use this if you want to return strings.
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
var newData = data1.Select(i => i.ToString()).Intersect(data2);
Use this if you want to return integers.
List<int> data1 = new List<int> {1,2,3,4,5};
List<string> data2 = new List<string>{"6","3"};
var newData = data1.Intersect(data2.Select(s => int.Parse(s));
Note that this will throw an exception if not all strings are numbers. So you could do the following first to check:
int temp;
if(data2.All(s => int.TryParse(s, out temp)))
{
// All data2 strings are int's
}
If you have objects, not structs (or strings), then you'll have to intersect their keys first, and then select objects by those keys:
var ids = list1.Select(x => x.Id).Intersect(list2.Select(x => x.Id));
var result = list1.Where(x => ids.Contains(x.Id));
From performance point of view if two lists contain number of elements that differ significantly, you can try such approach (using conditional operator ?:):
1.First you need to declare a converter:
Converter<string, int> del = delegate(string s) { return Int32.Parse(s); };
2.Then you use a conditional operator:
var r = data1.Count > data2.Count ?
data2.ConvertAll<int>(del).Intersect(data1) :
data1.Select(v => v.ToString()).Intersect(data2).ToList<string>().ConvertAll<int>(del);
You convert elements of shorter list to match the type of longer list. Imagine an execution speed if your first set contains 1000 elements and second only 10 (or opposite as it doesn't matter) ;-)
As you want to have a result as List, in a last line you convert the result (only result) back to int.
public static List<T> ListCompare<T>(List<T> List1 , List<T> List2 , string key )
{
return List1.Select(t => t.GetType().GetProperty(key).GetValue(t))
.Intersect(List2.Select(t => t.GetType().GetProperty(key).GetValue(t))).ToList();
}