How to search through combobox with a string containing a wildcat? - c#

I have a combo-box that contains lots of entries like this small extract
1R09ST75057
1R11ST75070
1R15ST75086
1R23ST75090
2R05HS75063
2R05ST75063
3R05ST75086
2R07HS75086
The user now enters some information in the form that result in a string being produced that has a wildcat (unknown) character in it at the second character position
3?05ST75086
I now want to take this string and search\filter through the combo-box list and be left with this item as selected or a small set of strings.
If I know the string without the wildcat I can use the following to select it in the Combo-box.
cmbobx_axrs75.SelectedIndex = cmbobx_axrs75.Items.IndexOf("2R05HS75063");
I thought I could first create a small subset that all have the first char the same then make a substring of each minus the first two chars and check this but I can have a large amount of entries and this will take too much time there must be an easier way?
Any ideas how I can do this with the wildcat in the string please?
Added info:
I want to end up with the selected item in the Combobox matching my string.
I choose from items on the form and result in string 3?05ST75086. I now want to take this and search to find which one it is and select it. So from list below
1R05ST75086
2R05ST75086
3R05ST75086
6R05ST75086
3R05GT75086
3R05ST75186
I would end up with selected item in Combo-box as
3R05ST75086

You could use regular expressions. Something like this:
string[] data = new string[]
{
"1R09ST75057",
"1R11ST75070",
"1R15ST75086",
"1R23ST75090",
"2R05HS75063",
"2R05ST75063",
"3R05ST75086",
"2R07HS75086"
};
string pattern = "3*05ST75086";
string[] results = data
.Where(x => System.Text.RegularExpressions.Regex.IsMatch(x, pattern))
.ToArray();

You can use a regular expression for this task. First, you need a method to convert your pattern string to Regex like this (it should handle "*" and "?" wildcards):
private static string ConvertWildCardToRegex(string value)
{
return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
}
Then you will use it like the following:
List<string> comboBoxValues = new List<string>()
{
"1R09ST75057",
"1R11ST75070",
"1R15ST75086",
"1R23ST75090",
"2R05HS75063",
"2R05ST75063",
"3R05ST75086",
"2R07HS75086"
};
string searchPattern = "3?05ST75086";
string patternAsRegex = ConvertWildCardToRegex(searchPattern);
var selected = comboBoxValues.FirstOrDefault(c => Regex.IsMatch(c, patternAsRegex));
if (selected != null)
{
int selectedIndex = comboBoxValues.IndexOf(selected);
}
This assumes you only care about first found match. If you need all matches then substitute FirstOrDefault(...) with Where(...) clause and swap "if" statement with a foreach loop.

Thanks to all that helped I used a combination of items from all answers so everyone helped me answer this.
I added this function from the answers as it seems a good idea, thanks
private static string ConvertWildCardToRegex(string value)
{
return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
}
Then I get the combo box items into a list. I search the list and make some more decisions based on the result of the search.
List<string> comboBoxValues = new List<string>();
for (int i = 0; i < cmbobx_in_focus.Items.Count; i++)
{
comboBoxValues.Add(cmbobx_in_focus.GetItemText(cmbobx_in_focus.Items[i]));
}
string[] results = comboBoxValues
.Where(x => Regex.IsMatch(x, ConvertWildCardToRegex(lbl_raster_used.Text)))
.ToArray();
I now have array called results which is easy to work with.

Related

Remove rows where column contains specific text

I want to remove all the rows of the data whose columns contains ? e.g. in around 100 rows for Column Status I am getting value as Unknown?, Error?, InProgress, Done
So , I want to remove all the rows which contains ?
Below are the code I am using
//I am splitting the string on the basis of delimeter ,
var data = from val in UserData
select val.Split(',');
//Below code is not working
var filterdata = from rows in data
where rows.Contains("?")
select rows;
You forgot to invert the contains:
string[] someStringArray = new string[]
{
"\"ABC\" ,\"Error?\",\"OK\"",
"\"DEF\",\"Inprogress\",\"FINE\"",
"1,2,3",
"?,2,3",
"1,?,3",
"4,5,6"
};
//I am splitting the string on the basis of delimeter ,
var data = from val in someStringArray
select val.Split(',');
//Below code is not working
var filterdata = from rows in data
where !rows.Contains("?") // "!" to select the rows WITHOUT "?"
select rows;
foreach (var item in filterdata)
{
foreach (var i in item)
{
Console.Write(i + ",");
}
Console.WriteLine();
}
return;
Result:
"DEF","Inprogress","FINE",
4,5,6,
This code is perfectly working, I think.
Beside this, I doing a wild guess: You're not searching for quesionmarks "?". The "?" is a character which is often shown if the character can't be shown in your expected encoding.
Have a look which number your chars have:
var chars = someStringArray.SelectMany(s => s.Select(c => c));
foreach (var item in chars.GroupBy(g => g.ToString() + " (" + ((int)g) + ")"))
{
Console.WriteLine(item.Key + ": " + item.Count());
}
Real questionmarks have a 63. If not you've got encoding problems..
You wrote:
I want to remove all the rows of the data whose columns contains "?"
You can never change the input sequence using LINQ functions. So you can't remove rows from your original data using LINQ.
What you can do, is use your data to create a new sequence that doesn't contain question marks. If desired, you can replace your original data with the new sequence.
Looking at your code, it seems that UserData is a sequence of strings, of which you expect that these strings contains comma separated values.
You want to split these CSV strings into their columns, but you don't want rows where any of your columns contain "?"
"A,?,B,C" => do not use this one, one of the column values equals "?"
"A,B,C" => use this one, none of the column values equal "?"
"A, Hello?, B" => use this one, although the second column contains a question mark
this second column is not equal to question mark
This is done as follows:
static readonly char[] separatorChars = new char[] {','}
const string questionMark = "?";
static readonly IEqualityComparer<string> comparer =
var rowsWithoutQuestionMarkValues = userData
// Split each line into column values, using comma as separator
.Select(line => line.Split(separatorChar)
// do not use the line if any of the columns equals the question mark
.Where(splitLine => !splitLine.Any(column => column == questionMark));
If your code might be running in a culture where a questionmark might look differently, for instance: "分号", consider using an IEqualityComparer<string>
readonly IEqualityComparer<string> comparer = GetStringComparerForMyCulture();
var result = ...
.Where(splitLine => !splitLine.Any(column => comparer.Equals(column, questionMark));

Filter an arraylist with condition

I have an ArrayList with multiples items on it, everyone of them is a String divided by commas "loglogs", the three first items are the localization (Destin, lat and long). I need to insert the Strings of these loglogs in buttons depending on its localization (based on that three parameters) in the button Tooltip or text programatically. I have all the button creation but I have to add the strings but there are more loglogs than buttons so...
I need to "filter" the ArrayList into another ArrayList, filter it depending on these three inital coordinates, I want to create another ArrayList but appending the strings that are identical in their three first elements of the arrayList. That way I will combine the "loglogs" into another "loglogsCondensed", with all the "localization" unique so I can add this part to my button and index creation.
foreach (String log in logslogs)
{
String[] colContent = log.Split(','); //splited the content with commas
Loglog log = new Loglog(); //Loglog is a class of logs with information in specific columns
log.Destin = colContent[0];
log.Lat = Convert.ToChar(colContent[1]);
log.Long = colContent[2];
log.Barcode = colContent[6];
log.Source = colContent[7];
log.SampleName = colContent[9];
AllLogs.Add(log);
I need to pass from logslogs with 1000 memebers to an ArrayList with less items, where the ones with the same location based on the three first items are appended as one item.
Suposse this is kind of easy if you know how to code properly (not my case). A thousand thanks only for read this out, even more to the people who try to help.
Best,
I have the solution!, probably is not going to win any contest of cleaneness but it does what I need!. I create an index to filter comparing the items depending of the three coordinates: Destin, Long and Lat. If they are the same I remove the last item and put the appended line in the last place and so on...
int c = 0; //Just to go the first time
//We create an index to compare the former with the "actual"
//log in every loop of the "foreach"
String IndiceDestin0 = string.Empty;
String IndiceLat0 = string.Empty;
String IndiceLong0 = string.Empty;
String IndiceDestin1;
String IndiceLat1;
String IndiceLong1;
foreach (String log in logslogs)
{
String[] LongContent = log.Split(',');
Loglog log = new Loglog();
log.Destin = LongContent[0];
log.Lat = Convert.ToChar(LongContent[1]);
log.Long = LongContent[2];
log.Barcode = LongContent[6];
log.Source = LongContent[7];
log.DestDestinBarcode = LongContent[8];
log.SampleName = LongContent[9];
AllLogs.Add(log);
//This only works once, the first time because we don't have a "former" data to compare we have to bypass the comparison
if (c == 0)
{
IndiceDestin0 = LongContent[0];
IndiceLat0 = LongContent[1];
IndiceLong0 = LongContent[2];
c++;
}
else
{
IndiceDestin1 = LongContent[0];
IndiceLat1 = LongContent[1];
IndiceLong1 = LongContent[2];
if (IndiceDestin0.Equals(IndiceDestin1) && IndiceLat0.Equals(IndiceLat1) && IndiceLong0.Equals(IndiceLong1))
{
int last = logsToButtons.Count - 1;
string oldLog = logsToButtons[last].ToString();
string appendedLog = oldLog + log;
//We remove the last "single" log to add the aggregated log
logsToButtons.RemoveAt(last);
logsToButtons.Add(appendedLog);
}
else
{
logsToButtons.Add(log);
}
IndiceDestin0 = IndiceDestin1;
IndiceLat0 = IndiceLat1;
IndiceLong0 = IndiceLong1;
c++;
}
}
I get to have a shorter version of the array but appending together the ones that have the same coordenates, thank you everybody for your help, I know is messy but it works!
Best,

If string in list occurs in string, then add to list

had a look around and found many similar questions but none matching mine exactly.
public bool checkInvalid()
{
invalidMessage = filterWords.Any(s => appmessage.Contains(s));
return invalidMessage;
}
If a string is found that matches a string in the list the boolean invalidMessage is set to true.
After this though I would like to be able to add each string found to a list. is there a way I can do this using .Contains() or can someone recommend me another way to go about this?
Many thanks.
Well, from your description, I thought here is what you want:
// Set of filtered words
string[] filterWords = {"AAA", "BBB", "EEE"};
// The app message
string appMessage = "AAA CCC BBB DDD";
// The list contains filtered words from the app message
List<string> result = new List<string>();
// Normally, here is what you do
// 1. With each word in the filtered words set
foreach (string word in filterWords)
{
// Check if it exists in the app message
if (appMessage.Contains(word))
{
// If it does, add to the list
result.Add(word);
}
}
But as you said, you want to use LINQ, so instead of doing a loop, you can do it like this:
// If you want to use LINQ, here is the way
result.AddRange(filterWords.Where(word => appMessage.Contains(word)));
If what you want is to gets the words in filterWords that are contained in appmessage you can use Where:
var words = filterWords.Where(s => appmessage.Contains(s)).ToList();

Compare results of 2 split strings?

I have two string inputs with that have been split so each item is distinguishable from the other (these items are product properties such as length, weight, finish, stain color, etc.). One string has the original values for the product while the other has the new values (whatever they may be--users can edit whichever product values they want).
Right now, I have the split strings producing the info that I want but I am not sure how to compare the results to each other since the individual product values are inside foreach loops.
This is what I have:
//checks to see which attributes have been changed/edited for the product
protected bool ifAttrChanged(string oldItm, string newItm)
{
bool retVal = false;
//get the original attributes of the product
string[] oldItms = oldItm.Split(',');
foreach (string oItm in oldItms)
{
if (oItm != "")
{
string[] oldThings = oItm.Split(',');
string oldies = oldThings.GetValue(0).ToString();
}
}
//get whatever new values have been entered for the product
string[] newItms = newItm.Split(',');
foreach (string nItm in newItms)
{
if (nItm != "")
{
string[] newThings = nItm.Split(',');
string newbies = newThings.GetValue(0).ToString();
}
}
if (newItms.ToString().Equals(oldItms.ToString(), StringComparison.Ordinal))
{
retVal = false;
Label3.Text += retVal.ToString() + "<br />";
}
else
{
retVal = true;
Label3.Text += retVal.ToString() + "<br />";
}
return retVal;
}
I would really like to compare the oldies string variable with the newbies string variable (weird names but I am not concerned about that) but they are each in their own foreach statement and I cannot access them elsewhere. How can I compare the old and new values of the two split strings successfully so I can obtain which values were changed and which values remained the same?
With all the strings splittend and stored in arrays (oldItems and newItems), and using System.Linq.
Try this:
var changedResults = newItems.Where(x => !oldItems.Any(y => x == y));
With this you will get a IEnumerable with all the string in newItems which no appear in oldItems array.
If you want to convert this to a list or something, add this:
var changedResults = newItems.Where(x => !oldItems.Any(y => x == y)).ToList();
I hope this helps
What is a "change"? Addition? Deletion? Modification?
If only addition, Oscar's method works. This is the same thing (set difference) but a little more concise:
var changedResults = newItems.Except(oldItems)
However, if a deletion is a "change" as well, you would need to consider it from both sides.
var changedResults = newItems.Except(oldItems).Union(oldItems.Except(newItems));
Since the sets are of only strings, there is no notion of modification.

Removing an element from list if it contains particular text in it

I have a C# method in which I look for certain text say username in a list with element in the format username + datetime and if any part of text matches the element in the list, then the entire element has to be removed from the list
Method to add to the c# List
string active_user = model.UserName.ToString();
string datetime = "(" + DateTime.Now + ")";
List<string> activeUsers = new List<string>();
if (activeUsers.Any(str => str.Contains(active_user)))
{
//do nothing
}
else
{
activeUsers.Add(active_user+datetime);
}
Now I would like a method that deletes the element if it matches the username or any part of element something like
if (activeUsers.Contains(active_user))
{
activeUsers.Remove(active_user);
}
While the other answers are correct, you should note that they will delete any matches. For example, active_user = "John" will remove "John", "John123", "OtherJohn", etc.
You can use regular expressions to test, or if user names don't have parentheses, do your test like this:
string comp = active_user + "("; // The ( is the start of the date part
activeUsers.RemoveAll(u => u.StartsWith(comp));
Also note, this is case sensitive.
You can do something like
activeUsers.RemoveAll(u => u.Contains(active_user));
That will match and remove all elements of activeUser that contain the text in active_user.
var user = activeUsers.FirstOrDefault(au => au.Contains(active_user);
if(user != null)
activeUsers.Remove(user);
if you are only wanting to remove the first match, else :
var users = activeUsers.Where(au => au.Contains(active_user);
foreach(var user in users)
activeUsers.Remove(user);
Or more simply, the RemoveAll method Eric answered with.
If i Want to remove Numeric String Values List Items from my List
List<ModelName> ModelList = new List<ModelName>();
var regex = new Regex(#"\d");
foreach(var item in ModelList.ToList())
{
if (regex.IsMatch(item.PropertyName))
{
ModelList.RemoveAll(t => t.PropertyName== item.PropertyName);//Or
ModelList.RemoveAll(t => t.PropertyName.Contains(item.PropertyName));//Or You Can Use Contains Method
}
}
return ModelList;
This will remove all items from list those having Numeric values as a string and return only Character String in List items

Categories