So I have been asked to remove tour codes that end with the letter G, GE, G=, or Z. The only bad thing is I believe we use this call for a lot of pages and that is the reason I cant alter the database call in the first place so I want to do this specifically for this one person. My code is calling an arrayList that fills with all the tourcodes we have. Is there any way I can remove the tours with the letters above. Here is what I got to work with.
public void LoadTourCodes()
{
ddlTourCode.Items.Clear();
if (ddlTourCode.Visible)
{
ddlTourCode.Items.Add(new ListItem(" ", ""));
ArrayList tourCodes;
tourCodes = EblTipTours.FindTourCodes();
foreach (string tourCode in tourCodes)
{
ddlTourCode.Items.Add(tourCode);
}
}
}
You can do it using LINQ, like this:
var toRemove = new []{"G", "GE", "G=", "Z"};
foreach (string tourCode in tourCodes.Where(code => !toRemove.Any(suffix => code.EndsWith(suffix)))) {
ddlTourCode.Items.Add(tourCode);
}
If you cannot use LINQ because it's a legacy system, you can rewrite the code like this:
string[] toRemove = new string[] {"G", "GE", "G=", "Z"};
foreach (string tourCode in tourCodes) {
bool good = true;
foreach (string suffix in toRemove) {
if (tourCode.EndsWith(suffix)) {
good = false;
break;
}
}
if (!good) continue;
ddlTourCode.Items.Add(tourCode);
}
Related
I have multiple objects in an array of which the format:
id_name_date_filetype.
I need to take all the objects with, let's say same id or same name and insert them in a new array.
With the GetFiles method I already have all the object in one array and I have their names but I don't know how to differentiate them.
I have a foreach I which I'll be going through all the objects but I'm kind of stuck.
Any hints as to what do I do?
//Process the files
string[] filelist = Directory.GetFiles(SourceDirectory, "*.tsv*", SearchOption.TopDirectoryOnly).Select(filename => Path.GetFullPath(filename)).Distinct().ToArray();
foreach (string file in filelist)
{
string[] fileNameSplit = file.Split('_');
switch (fileNameSplit.Last().ToLower())
{
case "assets.tsv":
assets = ReadDataFromCsv<Asset>(file);
break;
case "financialaccounts.tsv":
financialAccounts = ReadDataFromCsv<FinancialAccount>(file);
break;
case "households.tsv":
households = ReadDataFromCsv<Household>(file);
break;
case "registrations.tsv":
registrations = ReadDataFromCsv<Registration>(file);
break;
case "representatives.tsv":
representatives = ReadDataFromCsv<Representative>(file);
break;
}
}
// Find all files from one firm and insert them in a list
foreach (string file in filelist)
{
}
Here is a linq approach as I proposed it in my comment:
First get all distinct ID's from your filelist
string [] allDistinctIDs = filelist.Select(x=>x.Split('_').First()).Distinct(). ToArray();
now you can iterate through the list of ID's and compare each value
for (int i = 0; i < allDistinctIDs.Length; i++)
{
string [] allSameIDStrings = filelist.Where(x=>x.Split('_').First() == allDistinctIDs[i]).ToArray();
}
Basically you split every item by '_' and compare the first (id part) of the string with each item from your list of distinct ID's.
Another approach would be to use GroupBy.
// example input
string[] filelist = {
"123_Name1_xxx_Asset.tsv",
"456_Name2_xxx_Asset.tsv",
"123_Name3_xxx_HouseHold.tsv",
"456_Name4_xxx_HouseHold.tsv"};
IEnumerable<IGrouping<string, string>> ID_Groups = filelist.GroupBy(x=>x.Split('_').First());
This would give you a collection of all filenames grouped by the ID:
at each position in ID_Groups is a list of items with the same ID. You can filter them by fileName:
foreach (var id_group in ID_Groups)
{
assets = ReadDataFromCsv<Asset>(id_group.FirstOrDefault(x=>x.ToLower().Contains("assets.tsv")));
// and so on
households = ReadDataFromCsv<Household>(id_group.FirstOrDefault(x=>x.ToLower().Contains("households.tsv")));
}
You gotta define what is "Similar" to you. It could be the initial letter of the file name? Half of it? Whole filename?
This function should do more or less what you want without using Linq or something more complex than loops.
var IDOffileNameIWant = object.GetFiles()[0].id;
List<string> arrayThatContainsSimilar = new List<string>();
foreach(var file in object.GetFiles())
{
if(file.Name.Split('_')[0].Contains(IDOffileNameIWant))
{
arrayThatContainsSimilar.Add(file.Name);
}
}
It's very basic and can be refined, but you gotta give more details on what is the exact result you want to obtain.
Since you're still struggling, here's a working example:
List<string> files = new List<string>() {
"123_novica_file1", "123_novica_file3", "123_novica_file2", "456_myfilename_file1",
"789_myfilename_file1", "101_novica_file2", "102_novica_file3"};
List<string> filesbyID = new List<string>();
List<string> filesbyName = new List<string>();
string theIDPattern = "123";
string theFileNamePattern = "myfilename";
foreach(var file in files)
{
//splitting the filename and checking by ID
if(file.Split('_')[0].Contains(theIDPattern))
{
filesbyID.Add(file);
}
//splitting the filename and checking by name
if (file.Split('_')[1].Contains(theFileNamePattern))
{
filesbyName.Add(file);
}
}
Result:
files by id:
123_novica_file1
123_novica_file3
123_novica_file2
files by name:
456_myfilename_file1
789_myfilename_file1
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;
}
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
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 + ";");
...
}
I'm trying to write out the specific line of code that contains the IF statement. What appears to be happening if it never finds the code i'm looking to call in my if statement and i know it exists, it's a copy and paste. Also, how do i only write out the specific line that meets the if statement. Is there one where i should do a foreach? foreach (redsplitline in redsplitlines)
heres the code:
{
string linesplitnew = "ENDOB";
string[] redsplitlines = rdrred.ReadToEnd().Split(new string[] { linesplitnew }, StringSplitOptions.None);
string redpullline = "*BEGINOB\r\n6*";
string redpullline2 = "*BEGINOB\r\n13*";
if(redsplitlines.Contains(redpullline))
{
Console.WriteLine(redsplitlines);
}
else if(redsplitlines.Contains(redpullline2))
{
Console.WriteLine(redsplitlines);
}
}
Try this:
var lines = from line in redsplitlines
where line.Contains(redpullline) || line.Contains(redpullline2)
select line;
foreach (var l in lines)
Console.WriteLine(l);