Select row from List<string> where matches - c#

I have the following List<string>
List<string> RFD = new List<string>(File.ReadAllLines("FDIASNC"));
the file it is reading has this:
000821031300000000080
001921031300000000080
004221031300000000080
008121031300000000080
009321031300000000080
011221031300000000080
012221031300000000080
0128200313010000330790000033
207721031300000000080
So what I want is to find a match and select this line, for example if I want to read the line for "0128" it will be RFD[7] manually, but I want to search that line and output the line for manipulation... Any idea?
Thank you.
EDIT
I found it once I posted, I'm a dumb hehe... thank you for your answers, in 10 min I will select one as the correct :)

You can use LINQ to search:
var line = File.ReadAllLines("FDIASNC")
.FirstOrDefault(line => line.StartWith("0128"));
if (line != null)
{
//Do something with this line
}
You don't need to create a List<string> since ReadAllLines returns IEnumerable<string>
If your file is large, you might think to use deferred execution by ReadLines instead of loading all lines into memory

RFD.Where(r=>r.Contains("0128")).FirstOrDefault()

If you want to select exactly one line, that matches you criteria, use First or Single LINQ extension method. For example:
string str = RFD.First(line => line.StartWith("0128"));
returns 0128200313010000330790000033 string

Something like this?
using System.Linq;
// later in your program...
foreach (string match in RFD.Where(l => l.StartsWith("0128"))) {
Console.WriteLine(match);
}

try this:
string line = RFD.FirstOrDefault(line => line.StartsWith("0128"));
If there's no line with 0128 at the beginning then line is null

Related

Remove values from string using C#

I have following string in my aspx.cs page. These both strings are dynamic
string fromDB = "12,24,25,45,67,78,90" (its a dynamic string)
I have another string which has two or more values always as given below
string anotherStr = "24,67"
I am not getting an idea how to remove "anotherStr" values from "fromDB"
Finally I need "12,25,45,78,90". I am not getting an idea how to do this using c#.
using Linq:
string.Join(",", fromDB.Split(',').Except(anotherStr.Split(',')))
Split your (hard) problem into multiple (easy) problems:
Convert your comma-separated strings into lists (or arrays) of strings (using e.g. String.Split).
Find out how to remove all list entries from one list from a second list (using e.g. Enumerable.Except).
Convert your list back into a comma-separated string (using e.g. String.Join).
For all of these simpler problems, solutions can be found here on SO.
string fromDB = "12,24,25,45,67,78,90";
string anotherStr = "24,67";
var result = fromDB.Split(',').Except(anotherStr.Split(',')).ToList();
Console.WriteLine(string.Join(",", result));
Console.ReadLine();
This splits the strings into arrays, and then excludes any entries from fromDB that are also in anotherStr.
Note that the use of Except means that any duplicates will be removed from fromDB - as per https://stackoverflow.com/a/44547153/34092 .
You could do something like
HashSet<string> all = new HashSet<string>(fromDB.Split(',')),
toRemove = new HashSet<string>(anotherStr.Split(','));
foreach(var item in toRemove) {
all.Remove(item);
}
I suggest using HashSet<T> and Linq:
HashSet<string> exclude = new HashSet<string>(anotherStr.Split(','));
string result = string.Join(",", fromDB
.Split(',')
.Where(item => !exclude.Contains(item)));
Please, notice, that Except removes duplicates within fromDB while Where preserves them.
You split both strings to get two arrays, making the first a List<string> :
var fromDbList = fromDb.Split(',').ToList();
var anotherStrArray = anotherStr.Split(',');
You loop the second array, and delete its values from the first (which you cannot do on a String[], hence the previous ToList())
foreach (var valueToDelete in anotherStrArray)
{
fromDbList.Remove(valueToDelete);
}
Then you join the (now modified) first array to get a single string:
var finalString = String.Join(fromDbList, ",");

C# file line remove with arraylist

I am trying to make a class which will help me delete one specific line from a file. So I came up with the idea to put all lines in an arraylist, remove from the list the line i don't need, wipe clear my .txt file and write back the remaining objects of the list. My problem is that I encounter some sort of logical error i can't fint, that doesn't remove the line from the arraylist and writes it back again. Here's my code:
public class delete
{
public void removeline(string line_to_delete)
{
string[] lines = File.ReadAllLines("database.txt");
ArrayList list = new ArrayList(lines);
list.Remove(line_to_delete);
File.WriteAllText("database.txt", String.Empty);
using (var writer = new StreamWriter("database.txt"))
{
foreach (object k in lines)
{
writer.WriteLine(k);
}
}
}
}
What is that I am missing? I tried lots of things on removing a line from a text file that did not work. I tried this because it has the least file operations so far.
Thanks!
You can do:
var line_to_delete = "line to delete";
var lines = File.ReadAllLines("database.txt");
File.WriteAllLines("database.txt", lines.Where(line => line != line_to_delete));
File.WriteAllLines will overwrite the existing file.
Do not use ArrayList, there is a generic alternative List<T>. Your code is failing due to the use of ArrayList as it can only remove a single line matching the criteria. With List<T> you can use RemoveAll to remove all the lines matching criteria.
If you want to do the comparison with ignore case you can do:
File.WriteAllLines("database.txt", lines.Where(line =>
!String.Equals(line, line_to_delete, StringComparison.InvariantCultureIgnoreCase)));
I believe you're intending:
public static void RemoveLine(string line)
{
var document = File.ReadAllLines("...");
document.Remove(line);
document.WriteAllLines("..");
}
That would physically remove the line from the collection. Another approach would be to simply filter out that line with Linq:
var filter = document.Where(l => String.Compare(l, line, true) == 0);
You could do the Remove in an ArrayList proper documentation on how is here. Your code should actually work, all of these answers are more semantic oriented. The issue could be due to actual data, could you provide a sample? I can't reproduce with your code.

How to find last occurrence of an element using FindLast()

I want to find the last occurrence of an element in a list and know I must use the FindLast() to do that. However, I don't know how to implement and use this method.
Here is the code that I have:
// the list I need to check
orderedMetricsByNS = (List<Metric>) lmresponse.Metrics.OrderBy(metric => metric.Namespace);
foreach (Metric m in orderedMetricsByNS)
{
// want to use the FindLast() here
}
How do I retrieve the last occurrence of a metric like this? Thanks
What is the Predicate? You can use it like this:
var item = orderedMetricsByNS.FindLast(m => /* your condition */);
Or if you wanna just find the last item use Last method
var item = orderedMetricsByNS.Last();
Btw you can't cast from IOrderedEnumerable<T> to List<T>, your code will fail, you need to use ToList method.
orderedMetricsByNS = lmresponse.Metrics.OrderBy(metric => metric.Namespace).ToList();
You can use LINQ:
var last = orderedMetricByNS.LastOrDefault();
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.lastordefault%28v=vs.95%29.aspx

Searching List<T>

I have a List<string> containing file paths. How can I check if there is a particular file in my list e.g. file.txt? Preferably a method returning not a bool value but list element or element's index.
I've read the List<T> documentation but it only confused me as I'm a beginning programmer and my English isn't very good.
Use Where to get a list of values:
var found = fileList.
Where((f)=>System.IO.Path.GetFileName(f)
.Equals(SEARCH_VALUE,
StringComparison.InvariantCultureIgnoreCase));
or use FirstOrDefault for single element or null in case it's not found
If your list contains the full path (like c:\windows\system.ini") I would use System.IO.Path.GetFileName and also keep in mind to search case intenstive
var result = from f in files
where Path.GetFileName(f).Equals("file.txt",
StringComparison.InvariantCultureIgnoreCase)
select f;
bool found = result.Any();
The IndexOf method is what you need, if you want to find the path that exactly watches what you are looking for.
However, if you what to find paths in your list that end with a certain file name, you can do,
var matches = paths.Select((path, i) => new { Path = path, Index = i })
.Where(item => Path.GetFileName(item.Path).Equals(
"file.txt",
StringComparison.OrdinalIgnoreCase));
However, note that matches will be a sequence of 0 or more matches. So, you can do,
if (matches.Any())
{
// I found something.
foreach (var match in matches)
{
var matchIndex = match.Index;
var matchPath = match.Path;
}
}
else
{
// Oops, no matches.
}
or, if you only want the first.
var firstMatchPath = matches.First().Path;
would do.
If you just want the first value if there is one then you can do this.
var value = mylist.FirstOrDefault(x=>x.EndsWith("file.txt"));
or if you want to do something with each matching string.
foreach (string value in mylist.Where(x=>x.EndsWith("file.txt")) )
{
// Do whatever you intend with value.
}
or if you want a list of the indices of the values, then you could try this.
var indexValues = new List<int>();
foreach (string value in mylist.Where(x=>x.EndsWith("file.txt")) )
{
indexValues.Add(mylist.IndexOf(value));
}
Use LINQ (assuming you havethe paths as strings):
var found = from f in fileList where f.equals("file.txt") select f;
Considering that you have path and file name is located at the end of path:
//List of elements
List<string> foundElements = myInitialList.Where(s => s.EndsWith("file.txt")).ToList();
//List of Indexes (base on lift of elements here above)
List<int> indexList = new List<int>();
foundElements.ForEach(f => indexList.Add(myInitialList.IndexOf(f)));
It's not clear from your question, but it seems that the list will contain file paths, but what you are looking for is a filename.
The following code will give you the index of the first occurrence of a file called "file.txt" in the list of path names, or -1 if it isn't in the list.
Note how this uses Path.GetFileName(). This is so that it will match "c:\dir1\dir2\file.txt" and not "c:\dir1\dir2\wrongfile.txt".
int index = filenames.FindIndex(filename => Path.GetFileName(filename).Equals("file.txt", StringComparison.OrdinalIgnoreCase));
However, if you are searching for an entire path then you can do it like this:
int index = filenames.FindIndex(filename => filename.Equals("file.txt", StringComparison.OrdinalIgnoreCase));
Note how we do a comparison of the entire filename rather than using "EndsWith".
If the filenames are already all lowercase and you are comparing entire paths then you can do a simpler search:
int index = filenames.IndexOf("file.txt");
Or if they are all uppercase you'd have to do:
int index = filenames.IndexOf("FILE.TXT");

How to access a particular data in LINQ query result?

I know, this is very simple for you guys.
Please consider the following code:
string[] str = { "dataReader", "dataTable", "gridView", "textBox", "bool" };
var s = from n in str
where n.StartsWith("data")
select n;
foreach (var x in s)
{
Console.WriteLine(x.ToString());
}
Console.ReadLine();
Supposedly, it will print:
dataReader
dataTable
right?
What if for example I don't know the data, and what the results of the query will be (but I'm sure it will return some results) and I just want to print the second item that will be produced by the query, what should my code be instead of using foreach?
Is there something like array-indexing here?
You're looking forEnumerable.ElementAt.
var secondMatch = str.Where(item => item.StartsWith("data")) //consider null-test
.ElementAt(1);
Console.WriteLine(secondMatch); //ToString() is redundant
SinceWherestreams its results, this will be efficient - enumeration of the source sequence will be discontinued after the second match (the one you're interested in) has been found.
If you find that the implicit guarantee you have that the source will contain two matches is not valid, you can use ElementAtOrDefault.
var secondMatch = str.Where(item => item.StartsWith("data"))
.ElementAtOrDefault(1);
if(secondMatch == null) // because default(string) == null
{
// There are no matches or just a single match..
}
else
{
// Second match found..
}
You could use array-indexing here as you say, but only after you load the results into... an array. This will of course mean that the entire source sequence has to be enumerated and the matches loaded into the array, so it's a bit of a waste if you are only interested in the second match.
var secondMatch = str.Where(item => item.StartsWith("data"))
.ToArray()[1]; //ElementAt will will work too
you got a few options:
s.Skip(1).First();
s.ElementAt(1);
The first is more suited for scenarios where you want X elements but after the y first elements. The second is more clear when you just need a single element on a specific location

Categories

Resources