I have a linq list obtained from database in my Model. Now I have a string array obtained from my controller. I want to construct a statement
pseudo-code
List<object> objlist = db.objects.tolist();
string[] strarray; // obtained from a long code.
var k = objlist.Where(u => u.somecol == strarray[0] || u.somecol == strarray[1]........strarray[n]).toList();
I am little bit confused how to accomplish this since my strarray[] is variable length and can contain upto 1000 words.
You can check if an array contains some item using the Array.IndexOf<T> Method:
bool strarrayContainsX = Array.IndexOf<string>(strarray, "X") >= 0;
However, I'd recommend you use a HashSet<string> instead of a string array for anything more than a few items. The HashSet<T> Class provides a Contains Method to check if a set contains some item:
HashSet<string> strset = new HashSet<string>(strarray);
bool strsetContainsX = strset.Contains("X");
The resulting query then looks like this:
var k = objlist.Where(u => strset.Contains(u.somecol)).ToList();
Use Contains:
var k = objlist.Where(u => strarray.Contains(u.somecol)).toList();
Try this:
List<object> objlist = db.objects.tolist();
string[] strarray; // obtained from a long code.
var k = objlist.Where(u => strarray.Contains(u.somecol)).toList();
var k = objlist.Where(u => strarray.Any(x=>x == u.somecol)).ToList();
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();
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;
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();
}
I am reading a file that contains rows like
pathName; additionalString; maybeSomeNumbers
I read it using
var lines = File.ReadAllLines(fileListFile);
var fileListEntries = from line in lines
where !line.StartsWith("#")
select line.Split(';').ToArray();
This works well so far. However I would like to change the drive letter in the pathName. I could convert fileListEntries to an array and loop across elements [i][0], but is there a way that I could do this operation on the collection directly?
Use the LINQ extension method syntax in order to be able to use code blocks { ... } in the lambda expressions. If you do so, you have to include an explicit return-statement.
var fileListEntries = lines
.Where(l => !l.StartsWith("#"))
.Select(l => {
string[] columns = l.Split(';');
if (Path.IsPathRooted(column[0])) {
string root = Path.GetPathRoot(columns[0]);
columns[0] = Path.Combine(#"X:\", columns[0].Substring(root.Length));
}
return columns;
})
.ToArray();
I think you can do it inline with the LINQ.
File.ReadAllLines() returns a string array, so you should be able to perform Replace() on the line from the collection.
var replace = "The string to replace the drive letter";
var lines = File.ReadAllLines(fileListFile);
var fileListEntries = from line in lines
where !line.StartsWith("#")
select (line.Replace(line[0], replace).Split(';')).ToArray();
You could just call a method in your select that modifies the text in the manner that you would like.
static void Main(string[] args)
{
var fileListEntries = from line in lines
where !(line.StartsWith("#"))
select ( ModifyString(line));
}
private static string[] ModifyString(string line)
{
string[] elements = line.Split(';');
elements[0] = "modifiedString";
return elements;
}
lines.Where(l => !l.StartsWith("#").
Select(l => string.Concat(driveLetter, l.Substring(1))).
Select(l => l.Split(';');
I need an easy way to convert a List<int> to a string array.
I have:
var the_list = new List<int>();
the_list.Add(1);
the_list.Add(2);
the_list.Add(3);
string[] the_array = new string[the_list.Count];
for(var i = 0 ; i < the_array.Count; ++i)
the_array[i] = the_list[i].ToString();
...which looks to be very ugly to me.
Is there an easier way?
Note: I'm looking for an easier way - not necessarily a faster way.
Use LINQ:
string[] the_array = the_list.Select(i => i.ToString()).ToArray();
I know you have a good answer, but you don't need LINQ or Select. You can do it with a ConvertAll and an anonymous method. Like this:
var list = new List<int>();
....
var array = list.ConvertAll( x => x.ToString() ).ToArray();
Similar idea, but I think this is not linq. in case that matters.
Sorry, I don't have .NET installed on this machine, so totally untested:
var theList = new List<int>() { 1, 2, 3 };
var theArray = theList.Select(e => e.ToString()).ToArray(); // Lambda Form
var theArray = (from e in theList select e.ToString()).ToArray(); // Query Form
List has a ToArray() method. It will save you typing but probably won't be more efficient.
Because your list only has a number, you can easily convert them to a string. Just create a loop and convert its members to the string.
string[] the_array = new string[the_list.Count];
int i=0;
foreach(var item in the_list)
{
the_array[i] = item.ToString();
i++;
}