How to create a readable List<string> output? - c#

My code is as follows:
public List<string> connect(String query_physician, String query_institution)
{
Regex pattern = new Regex(#"(?<=""link""\:\s"")[^""]*(?="")");
MatchCollection linkMatches = pattern.Matches(customSearchResult);
var list = new List<string>();
list = linkMatches.Cast<Match>().Select(match => match.Value).ToList(); //put the links into a list?!
foreach (var item in list) //take each item (link) out of the list...
{
return item; // ...and return it?! //Error, because item is a string
}
return null;
}
Like you see, I want to return each link (as a readable list of my json result and display it in my RichTextBox, but I know, var item is a string. Otherwise it doesn´t work. Either I become an unreadable list, or a string (with string.Join(.....Cast<>()).
Do I have this right, string.Join(.....Cast<>()) adds the single strings together? Still, I don't want them together. Anyway, do you know a way to solve this problem?
By the way, return null is only a wildcard.

As I understand it is continuation of your previous question. Assuming you have this function (I simplified it a bit):
public List<string> connect(String query_physician, String query_institution)
{
...
return Regex.Matches(customSearchResult, #"(?<=""link""\:\s"")[^""]*(?="")")
.Cast<Match>()
.Select(m => m.Value)
.ToList();
}
You can do the following:
List<string> list = connect("", "");
string linksFormatted = string.Join(",", list);
To show the content in RichTextBox:
richTextBox1.AppendText(string.Join(Environment.NewLine, list));

Look at your method signature return type is List of string no string,
so much simplest approach:
public List<string> connect(String query_physician, String query_institution)
{ ...
//restults container
List<string> resultContainer = new List<String>();
Regex pattern = new Regex(#"(?<=""link""\:\s"")[^""]*(?="")");
MatchCollection linkMatches = pattern.Matches(customSearchResult);
var list = new List<string>();
list = linkMatches.Cast<Match>().Select(match => match.Value).ToList(); //put the links into a list?!
foreach (var item in list) //take each item (link) out of the list...
{
//add item to list
resultContainer.Add(item);
}
return resultContainer;
}

Related

Get the Substrings within the List<string> collection using Linq

I've a collection list.
List<string> mycollections = new List<string>(new string[]
{
"MyImages/Temp/bus.jpg",
"MyImages/Temp/car.jpg",
"MyImages/Temp/truck.jpg",
"MyImages/Temp/plane.jpg",
"MyImages/Temp/ship.jpg",
});
I required only files in a List such asbus.jpg, car.jpg...... Here i do not need "MyImages/Temp/" portion of the string in the same list.
I tried with Substring and Split with Linq queries but couldn't get the expected result.
Use Path.GetFileName instead of substring like:
var fileNames = mycollections.Select(r => Path.GetFileName(r)).ToList();
For output:
var fileNames = mycollections.Select(r => Path.GetFileName(r));
foreach (var item in fileNames)
{
Console.WriteLine(item);
}
Output:
bus.jpg
car.jpg
truck.jpg
plane.jpg
ship.jpg
How about this:
mycollections.Select(s => s.Split('/').Last());
That will split each string by slashes and return the last item.

How do I order this list of site URLs in C#?

I have a list of site URLs,
/node1
/node1/sub-node1
/node2
/node2/sub-node1
The list is given to me in a random order, I need to order it so the the top level is first, followed by sub-levels and so on (because I cannot create /node2/sub-node1 without /node2 existing). Is there a clean way to do this?
Right now I'm just making a recursive call, saying if I can't create sub-node1 because node2 exists, create node2. I'd like to have the order of the list determine the creation and get rid of my recursive call.
My first thought was ordering by length of the string... but then I thought of a list like this, that might include something like aliases for short names:
/longsitename/
/a
/a/b/c/
/a
/a/b/
/otherlongsitename/
... and I thought a better option was to order by the number of level-separator characters first:
IEnumerable<string> SortURLs(IEnumerable<string> urls)
{
return urls.OrderBy(s => s.Count(c => c == '/')).ThenBy(s => s);
}
Then I thought about it some more and I saw this line in your question:
I cannot create /node2/sub-node1 without /node2 existing
Aha! The order of sections or within a section does not really matter, as long as children are always listed after parents. With that in mind, my original thought was okay and ordering by length of the string alone should be just fine:
IEnumerable<string> SortURLs(IEnumerable<string> urls)
{
return urls.OrderBy(s => s.Length);
}
Which lead me at last to wondering why I cared about the length at all? If I just sort the strings, regardless of length, strings with the same beginning will always sort the shorter string first. Thus, at last:
IEnumerable<string> SortURLs(IEnumerable<string> urls)
{
return urls.OrderBy(s => s);
}
I'll leave the first sample up because it may be useful if, at some point in the future, you need a more lexical or logical sort order.
Is there a clean way to do this?
Just sorting the list of URI's using a standard string sort should get you what you need. In general, "a" will order before "aa" in a string sort, so "/node1" should end up before "/node1/sub-node".
For example:
List<string> test = new List<string> { "/node1/sub-node1", "/node2/sub-node1", "/node1", "/node2" };
foreach(var uri in test.OrderBy(s => s))
Console.WriteLine(uri);
This will print:
/node1
/node1/sub-node1
/node2
/node2/sub-node1
Perhaps this works for you:
var nodes = new[] { "/node1", "/node1/sub-node1", "/node2", "/node2/sub-node1" };
var orderedNodes = nodes
.Select(n => new { Levels = Path.GetFullPath(n).Split('\\').Length, Node = n })
.OrderBy(p => p.Levels).ThenBy(p => p.Node);
Result:
foreach(var nodeInfo in orderedNodes)
{
Console.WriteLine("Path:{0} Depth:{1}", nodeInfo.Node, nodeInfo.Levels);
}
Path:/node1 Depth:2
Path:/node2 Depth:2
Path:/node1/sub-node1 Depth:3
Path:/node2/sub-node1 Depth:3
var values = new string[]{"/node1", "/node1/sub-node1" ,"/node2", "/node2/sub-node1"};
foreach(var val in values.OrderBy(e => e))
{
Console.WriteLine(val);
}
The best is to use natural sorting since your strings are mixed between strings and numbers. Because if you use other sorting methods or techniques and you have like this example:
List<string> test = new List<string> { "/node1/sub-node1" ,"/node13","/node10","/node2/sub-node1", "/node1", "/node2" };
the output will be:
/node1
/node1/sub-node1
/node10
/node13
/node2
/node2/sub-node1
which is not sorted.
You can look at this Implementation
If you mean you need all the first level nodes before all the second level nodes, sort by the number of slashes /:
string[] array = {"/node1","/node1/sub-node1", "/node2", "/node2/sub-node1"};
array = array.OrderBy(s => s.Count(c => c == '/')).ToArray();
foreach(string s in array)
System.Console.WriteLine(s);
Result:
/node1
/node2
/node1/sub-node1
/node2/sub-node1
If you just need parent nodes before child nodes, it doesn't get much simpler than
Array.Sort(array);
Result:
/node1
/node1/sub-node1
/node2
/node2/sub-node1
Recursion is actually exactly what you should use, since this is most easily represented by a tree structure.
public class PathNode {
public readonly string Name;
private readonly IDictionary<string, PathNode> _children;
public PathNode(string name) {
Name = name;
_children = new Dictionary<string, PathNode>(StringComparer.InvariantCultureIgnoreCase);
}
public PathNode AddChild(string name) {
PathNode child;
if (_children.TryGetValue(name, out child)) {
return child;
}
child = new PathNode(name);
_children.Add(name, child);
return child;
}
public void Traverse(Action<PathNode> action) {
action(this);
foreach (var pathNode in _children.OrderBy(kvp => kvp.Key)) {
pathNode.Value.Traverse(action);
}
}
}
Which you can then use like this:
var root = new PathNode(String.Empty);
var links = new[] { "/node1/sub-node1", "/node1", "/node2/sub-node-2", "/node2", "/node2/sub-node-1" };
foreach (var link in links) {
if (String.IsNullOrWhiteSpace(link)) {
continue;
}
var node = root;
var lastIndex = link.IndexOf("/", StringComparison.InvariantCultureIgnoreCase);
if (lastIndex < 0) {
node.AddChild(link);
continue;
}
while (lastIndex >= 0) {
lastIndex = link.IndexOf("/", lastIndex + 1, StringComparison.InvariantCultureIgnoreCase);
node = node.AddChild(lastIndex > 0
? link.Substring(0, lastIndex) // Still inside the link
: link // No more slashies
);
}
}
var orderedLinks = new List<string>();
root.Traverse(pn => orderedLinks.Add(pn.Name));
foreach (var orderedLink in orderedLinks.Where(l => !String.IsNullOrWhiteSpace(l))) {
Console.Out.WriteLine(orderedLink);
}
Which should print:
/node1
/node1/sub-node1
/node2
/node2/sub-node-1
/node2/sub-node-2

See if items in a string list contain a certain string

Basically i have a string list as such:
/forum/
/phpld/
/php/
Now i want to check if any of the url:
http://www.url.com/forum/
contains any values from the string list.
In the above case it should match because /forum/ is in the url.
I was thinking something like this:
foreach (string filter in _filterList)
{
if (PAGEURL.Trim().Contains(filter.Trim()))
{
_parseResultsFinal.Add(PAGEURL);
filteredByURL++;
break;
}
}
But i cannot get the above to be accurate
How would i do this? :)
Try this:
_filterList.Any(filter => PAGEURL.Trim().Contains(filter.Trim()));
You may do PAGEURL = PAGEURL.Trim() before this expression to not run it each time.
String.Contains() is case-sensitive and culture-insensitive, so if there are any case differences that could be the cause of the 'inaccuracy' that you are experiencing.
If you suspect this may be the problem (or even as a viable alternative) you can try this as the 'if' clause:
if (PAGEURL.Trim().IndexOf(filter.Trim(), StringComparison.OrdinalIgnoreCase) >= 0)
I'm not abundantly clear on what you want to do here, it seems as though if a URL contains any of the filters then you want to add the URL to the list.
List<string> parseResultsFinal = new List<string>();
if (_filterList.Any(x => PAGEURL.Contains(x))
{
parseResultsFinal.Add(PAGEURL);
}
Try to use that.
I would try the following:
var trimmedUrl = PageURL.Replace("http://", "");
var parts = trimmedUrl.Split("/");
var filterList = new List<string> { "forum", "phpld", "php" }
var anyContains = parts.Any(o => filterList.contains(o));
I'd change segments filters to simple words (without slashes, trimmed before adding to filter list):
var _filterList = new List<string>()
{
"forum", "phpld", "php"
};
And used regex to search for segments in url (ignore case, optional slash at the end of url)
bool IsSegmentInUrl(string url, string segment)
{
string pattern = String.Format(".*/{0}(/|$)", segment);
return Regex.IsMatch(url, pattern, RegexOptions.IgnoreCase);
}
Usage:
if (_filterList.Any(filter => IsSegmentInUrl(PAGEURL, filter))
{
_parseResultsFinal.Add(PAGEURL);
filteredByURL++;
}
More readable solution - create extensions method
public static bool ContainsSegment(this string url, string segment)
{
string pattern = String.Format("http://.*/{0}(/|$)", segment);
return Regex.IsMatch(url, pattern, RegexOptions.IgnoreCase);
}
Now code looks very self-describing:
if (_filterList.Any(filter => PAGEURL.ContainsSegment(filter))
{
_parseResultsFinal.Add(PAGEURL);
filteredByURL++;
}

extracting the common prefixes from a list of strings

I have a list of strings, such as:
{ abc001, abc002, abc003, cdef001, cdef002, cdef004, ghi002, ghi001 }
I want to get all the common unique prefixes; for example, for the above list:
{ abc, cdef, ghi }
How do I do that?
var list = new List<String> {
"abc001", "abc002", "abc003", "cdef001",
"cdef002", "cdef004", "ghi002", "ghi001"
};
var prefixes = list.Select(x = >Regex.Match(x, #"^[^\d]+").Value).Distinct();
It may be a good idea to write a helper class to represent your data. For example:
public class PrefixedNumber
{
private static Regex parser = new Regex(#"^(\p{L}+)(\d+)$");
public PrefixedNumber(string source) // you may want a static Parse method.
{
Match parsed = parser.Match(source); // think about an error here when it doesn't match
Prefix = parsed.Groups[1].Value;
Index = parsed.Groups[2].Value;
}
public string Prefix { get; set; }
public string Index { get; set; }
}
You need to come up with a better name, of course, and better access modifiers.
Now the task is quite easy:
List<string> data = new List<string> { "abc001", "abc002", "abc003", "cdef001",
"cdef002", "cdef004", "ghi002", "ghi001" };
var groups = data.Select(str => new PrefixedNumber(str))
.GroupBy(prefixed => prefixed.Prefix);
The result is all data, parsed, and grouped by the prefix.
You can achieve that using Regular Expression to select the text part, and then use HashSet<string> to add that text part so no duplication added:
using System.Text.RegularExpressions;
//simulate your real list
List<string> myList = new List<string>(new string[] { "abc001", "abc002", "cdef001" });
string pattern = #"^(\D*)\d+$";
// \D* any non digit characters, and \d+ means followed by at least one digit,
// Note if you want also to capture string like "abc" alone without followed by numbers
// then the pattern will be "^(\D*)$"
Regex regex = new Regex(pattern);
HashSet<string> matchesStrings = new HashSet<string>();
foreach (string item in myList)
{
var match = regex.Match(item);
if (match.Groups.Count > 1)
{
matchesString.Add(match.Groups[1].Value);
}
}
result:
abc, cde
Assuming that your prefix is all alpha characters and terminited by the first non-alpha character, you could use the following LINQ expression
List<string> listOfStrings = new List<String>()
{ "abc001d", "abc002", "abc003", "cdef001", "cdef002", "cdef004", "ghi002", "ghi001" };
var prefixes = (from s in listOfStrings
select new string(s.TakeWhile(c => char.IsLetter(c)).ToArray())).Distinct();

get values from string

in my variable:
string selectedObjects;
i have one long value like:
"123;132;213;231;"
i want to get 4 times values as: "123;" , "132;" , "213;" and "231;".
i tryed with foreach as:
public ActionResult ShowHistory(string selectedObjects)
{
foreach (string item in selectedObjects)
{
item = selectedObjects.Split(';');
}
but it doesnt work. how can i do that?
The flow is incorrect. Split returnes an array through which you should than iterate, using foreach if that's your choice. So:
foreach (string item in selectedObjects.Split(';'))
{
// do whatever you want with the items
}
You can use a regular expression:
foreach (Match m in Regex.Matches("123;132;213;231;", #"\d+;"))
string value = m.Value; //Do something worthwhile with the value.
All of the other answers are wrong or overkill - unless I'm missing something.
public ActionResult ShowHistory(string selectedObjects)
{
foreach (string tempItem in selectedObjects.Split(new []{';'}, StringSplitOptions.RemoveEmptyEntries))
{
string item = tempItem + ";"; // Add back on the ; character
}
// .. do something
The RemoveEmptyEntries is required, otherwise, you'll get an empty string at the end (because your input string ends with ";"). Also, string.Split does not preserve the separator char, so you need to add it back in if you want it (hence the tempItem).
Split returns an array of string.
string selectedObjects = ...;
foreach (string item in selectedObjects.Split(';'))
{
// do work
}
foreach(string item in selectedObjects.Split(new [] {';'},
StringSplitOptions.RemoveEmptyEntries)
.Select( x=> x+";"))
{
//process item
}
Split method returns array of string, try somehting like this
string selectedObjects = "123;132;213;231;";
string[] s = selectedObjects.Split(';');
foreach (string item in s )
{
Console.Writeline(item.ToString());
}
You need to append the semi-colon again after splitting.
public ActionResult ShowHistory(string selectedObjects)
{
var items = selectedObjects.Split(';')
.Where(i => !string.IsNullOrEmpty(i))
.Select(i => i + ";");
...
}
Or (if you can guarantee that exact format)
public ActionResult ShowHistory(string selectedObjects)
{
var items = selectedObjects.TrimEnd(';')
.Split(';')
.Select(i => i + ";");
...
}

Categories