how to get items between the search parameters - c#

Work on C#.I have a list named as InputList .From this list I have to search Some string.After search I want to select all item between the search parameter.Bellow picture discribe in detail.
Text Input File:
Collection :
After read the textFile I store data in dataset then,convert the dataset as collection .From this collection i want to get valuse between the search parameters.
I write the bellow syntax but r3 result can not satisfy me.
var InputList = (from p in ds.Tables["InputFile"].Rows.Cast<DataRow>().ToArray() select p.ItemArray).ToList();
var r3 = (from c in InputList
where c.Any(e => e.ToString().Contains("Loading"))
select c).ToList();
If have any query plz ask.Thanks in advance.

To get the results between queries, the SkipWhile() and TakeWhile() would work (both have variants that give the index to the predicate), but I don't think that is quite what you want given your image.
var loadingIndexes = InputList.Select((r, i) => new { Row=row, Index=i })
.Where(x => x.Row.Any(e =>
e.ToString().Contains("Loading"))
.Select(x => x.Index);
var betweenLines = loadingIndexes
.Select(i => InputList
.Skip(i)
.TakeWhile(r => !r.Any(e =>
e.ToString().Contains("FULL")))
.ToList())
.ToList();
Here betweenLines is a List of Lists of DataRows, where each list is between a DataRow containing the string "Loading" (inclusive) and the next `DataRow" containing the string "FULL" (exclusive).

Related

How to do in this in Linq C#

So far, I have this:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)));
Configuration folder will contain pairs of files:
abc.json
abc-input.json
def.json
def-input.json
GetReportName() method strips off the "-input" and title cases the filename, so you end up with a grouping of:
Abc
abc.json
abc-input.json
Def
def.json
def-input.json
I have a ReportItem class that has a constructor (Name, str1, str2). I want to extend the Linq to create the ReportItems in a single statement, so really something like:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)))
**.Select(x => new ReportItem(x.Key, x[0], x[1]));**
Obviously last line doesn't work because the grouping doesn't support array indexing like that. The item should be constructed as "Abc", "abc.json", "abc-input.json", etc.
If you know that each group of interest contains exactly two items, use First() to get the item at index 0, and Last() to get the item at index 1:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)))
.Where(g => g.Count() == 2) // Make sure we have exactly two items
.Select(x => new ReportItem(x.Key, x.First(), x.Last()));
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x))).Select(x => new ReportItem(x.Key, x.FirstOrDefault(), x.Skip(1).FirstOrDefault()));
But are you sure there will be exactly two items in each group? Maybe has it sence for ReportItem to accept IEnumerable, not just two strings?

LINQ query that combines grouping and sorting

I am relatively new to LINQ and currently working on a query that combines grouping and sorting. I am going to start with an example here. Basically I have an arbitrary sequence of numbers represented as strings:
List<string> sNumbers = new List<string> {"34521", "38450", "138477", "38451", "28384", "13841", "12345"}
I need to find all sNumbers in this list that contain a search pattern (say "384")
then return the filtered sequence such that the sNumbers that start with the search pattern ("384") are sorted first followed by the remaining sNumbers that contain the search pattern somewhere. So it will be like this (please also notice the alphabetical sort with in the groups):
{"38450", "38451", "13841", "28384", "138477"}
Here is how I have started:
outputlist = (from n in sNumbers
where n.Contains(searchPattern
select n).ToList();
So now we have all number that contain the search pattern. And this is where I am stuck. I know that at this point I need to 'group' the results into two sequences. One that start with the search pattern and other that don't. Then apply a secondary sort in each group alphabetically. How do I write a query that combines all that?
I think you don't need any grouping nor list splitting for getting your desired result, so instead of answer about combining and grouping I will post what I would do to get desired result:
sNumbers.Where(x=>x.Contains(pattern))
.OrderByDescending(x => x.StartsWith(pattern)) // first criteria
.ThenBy(x=>Convert.ToInt32(x)) //this do the trick instead of GroupBy
.ToList();
This seems fairly straight forward, unless I've misunderstood something:
List<string> outputlist =
sNumbers
.Where(n => n.Contains("384"))
.OrderBy(n => int.Parse(n))
.OrderByDescending(n => n.StartsWith("384"))
.ToList();
I get this:
var result = sNumbers
.Where(e => e.StartsWith("384"))
.OrderBy(e => Int32.Parse(e))
.Union(sNumbers
.Where(e => e.Contains("384"))
.OrderBy(e => Int32.Parse(e)));
Here the optimized version which only needs one LINQ statement:
string match = "384";
List<string> sNumbers = new List<string> {"34521", "38450", "138477", "38451", "28384", "13841", "12345"};
// That's all it is
var result =
(from x in sNumbers
group x by new { Start = x.StartsWith(match), Contain = x.Contains(match)}
into g
where g.Key.Start || g.Key.Contain
orderby !g.Key.Start
select g.OrderBy(Convert.ToInt32)).SelectMany(x => x);
result.ToList().ForEach(x => Console.Write(x + " "));
Steps:
1.) Group into group g based on StartsWith and Contains
2.) Just select those groups which contain the match
3.) Order by the inverse of the StartsWith key (So that StartsWith = true comes before StartsWith = false)
4.) Select the sorted list of elements of both groups
5.) Do a flatMap (SelectMany) over both lists to receive one final result list
Here an unoptimized version:
string match = "384";
List<string> sNumbers = new List<string> {"34521", "38450", "138477", "38451", "28384", "13841", "12345"};
var matching = from x in sNumbers
where x.StartsWith(match)
orderby Convert.ToInt32(x)
select x;
var nonMatching = from x in sNumbers
where !x.StartsWith(match) && x.Contains(match)
orderby Convert.ToInt32(x)
select x;
var result = matching.Concat(nonMatching);
result.ToList().ForEach(x => Console.Write(x + " "));
Linq has an OrderBy method that allows you give a custom class for deciding how things should be sorted. Look here: https://msdn.microsoft.com/en-us/library/bb549422(v=vs.100).aspx
Then you can write your IComparer class that takes a value in the constructor, then a Compare method that prefers values that start with that value.
Something like this maybe:
public class CompareStringsWithPreference : IComparer<string> {
private _valueToPrefer;
public CompareStringsWithPreference(string valueToPrefer) {
_valueToPrefer = valueToPrefer;
}
public int Compare(string s1, string s2) {
if ((s1.StartsWith(_valueToPrefer) && s2.StartsWith(_valueToPrefer)) ||
(!s1.StartsWith(_valueToPrefer) && !s2.StartsWith(_valueToPrefer)))
return string.Compare(s1, s2, true);
if (s1.StartsWith(_valueToPrefer)) return -1;
if (s2.StartsWith(_valueToPrefer)) return 1;
}
}
Then use it like this:
outputlist = (from n in sNumbers
where n.Contains(searchPattern)
select n).OrderBy(n, new CompareStringsWithPreference(searchPattern))ToList();
You can create a list with strings starting with searchPattern variable and another containing searchPattern but not starting with (to avoid repeating elements in both lists):
string searchPattern = "384";
List<string> sNumbers = new List<string> { "34521", "38450", "138477", "38451", "28384", "13841", "12345" };
var list1 = sNumbers.Where(s => s.StartsWith(searchPattern)).OrderBy(s => s).ToList();
var list2 = sNumbers.Where(s => !s.StartsWith(searchPattern) && s.Contains(searchPattern)).OrderBy(s => s).ToList();
var outputList = new List<string>();
outputList.AddRange(list1);
outputList.AddRange(list2);
Sorry guys, after reading through the responses, I realize that I made a mistake in my question. The correct answer would be as follows: (sort by "starts with" first and then alphabetically (not numerically)
// output: {"38450", "38451", "13841", "138477", "28384"}
I was able to achieve that with the following query:
string searchPattern = "384";
List<string> result =
sNumbers
.Where(n => n.Contains(searchpattern))
.OrderBy(s => !s.StartsWith(searchpattern))
.ThenBy(s => s)
.ToList();
Thanks

How to c# List<> order by and Group by according to parameters?

I have a class and its List
abc cs = new abc();
List<abc> Lst_CS = new List<abc>();
and I set some value by HidenField in foreach loop
foreach (blah blah)
{
cs = new abc{
No = VKNT,
GuidID=hdnGuidID.Value.ToString(),
RecID=hdnRecID.Value.ToString(),
Date=HdnDate.Value.ToString()
};
Lst_CS.Add(cs);
}
and finally I get a List_CS and I order by Lst_CS according to Date like this;
IEnumerable<abc> query = Lst_CS.OrderBy(l => l.Date).ToList();
but in extra, I want to group by according to No.
Briefly, I want to order by Date and then group by No on Lst_CS How can I do ?
Thanks for your answer
Well you just just do the ordering then the grouping like so:
Lst_CS.OrderBy(l => l.Date)
.GroupBy(l => l.No)
.ToList();
Each list of items in each group will be ordered by date. The groupings will be in the order that they are found when the entire list is ordered by date.
Also your ForEach can be done in one Linq statement, then combined with the ordering and grouping:
var query = blah.Select(b => new abc{
No = VKNT,
GuidID=hdnGuidID.Value.ToString(),
RecID=hdnRecID.Value.ToString(),
Date=HdnDate.Value.ToString()
})
.OrderBy(l => l.Date)
.GroupBy(l => l.No)
.ToList();

Counting grouped data with Linq to Sql

I have a database of documents in an array, each with an owner and a document type, and I'm trying to get a list of the 5 most common document types for a specific user.
var docTypes = _documentRepository.GetAll()
.Where(x => x.Owner.Id == LoggedInUser.Id)
.GroupBy(x => x.DocumentType.Id);
This returns all the documents belonging to a specific owner and grouped as I need them, I now need a way to extract the ids of the most common document types. I'm not too familiar with Linq to Sql, so any help would be great.
This would order the groups by count descending and then take the top 5 of them, you could adapt to another number or completely take out the Take() if its not needed in your case:
var mostCommon = docTypes.OrderByDescending( x => x.Count()).Take(5);
To just select the top document keys:
var mostCommonDocTypes = docTypes.OrderByDescending( x => x.Count())
.Select( x=> x.Key)
.Take(5);
You can also of course combine this with your original query by appending/chaining it, just separated for clarity in this answer.
Using the Select you can get the value from the Key of the Grouping (the Id) and then a count of each item in the grouping.
var docTypes = _documentRepository.GetAll()
.Where(x => x.Owner.Id == LoggedInUser.Id)
.GroupBy(x => x.DocumentType.Id)
.Select(groupingById=>
new
{
Id = groupingById.Key,
Count = groupingById.Count(),
})
.OrderByDescending(x => x.Count);

Searching a list to get index values in c#

I have a string comma separated list of some data. I have another list of strings of keywords that i want to search for in the first list. I want to have returned to me the index of all the elements in the first list that do no contain any of the keywords in the second list. For example:
List 1:
Student,101256,Active
Professor,597856,Active
Professor,697843,Inactive
Student,329741,Active
Student,135679,Inactive
Student,241786,Inactive
List 2:
697843
241786
My query on List 1 should be, give me all the index of all the elements that do not contain any of the elements of list 2. Therefore, the return list of indices should be 0,1,3,4. Is there any way to accomplish this?
Thanks in advance!
Edit: This is my try:
List<int> index = list1
.Select((s, i) => new { s, i })
.Where(e => !list2.Contains(e.s))
.Select(e => e.i).ToList();
You will need to reference System.Linq, this has now been edited to include the !Student filter
var list1 = new List<string> {
{"Student,101256,Active"},
{"Professor,597856,Active"},
{"Professor,697843,Inactive"},
{"Student,329741,Active"},
{"Student,135679,Inactive"},
{"Student,241786,Inactive"}
};
var list2 = new List<string> {{"697843"}, {"241786"}};
var result = list1
.Select((item,i)=> new {index=i,value=item})
.Where(item => !item.value.StartsWith("Student"))
.Where(item => !item.value.Split(',').Any(j => list2.Contains(j)))
.Select(item=>item.index)
.ToList();
The first select extracts the index before filtering, the pre-edited version calculated the index after the filter and so was incorrect.

Categories