Searching specific item in ObservableCollection - c#

I'm working on a SignalR WPF application. Im sending messages from Windows Phone. I want to find specific item in that collection.
My view model:
public ViewModel()
{
Messages = new ObservableCollection<string>();
_connection = new HubConnection("http://localhost:49671/");
_dataHub = _connection.CreateHubProxy("dataHub");
}
public ObservableCollection<string> Messages
{
get { return _messages; }
set
{
if (Equals(value, _messages)) return;
_messages = value;
OnPropertyChanged("Messages");
}
}
public async Task Login(string roomName, string userName)
{
_userName = userName;
_roomName = roomName;
await _connection.Start();
await _dataHub.Invoke("JoinRoom", new object[] { _roomName, _userName });
_dataHub.Subscribe("ReceiveMessage").Received += list =>
Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() =>
Messages.Add(list[0].ToString())));
}
Codes that I tried to search
var asd2 = App.MainViewModel.Messages.Where(a => a.Contains("on"));
var on = App.MainViewModel.Messages.IndexOf(App.MainViewModel.Messages.Where(x => x == "on").FirstOrDefault());
List<string> asd = App.MainViewModel.Messages.Where(a => a.Contains("on")).ToList();
var q = App.MainViewModel.Messages.IndexOf(App.MainViewModel.Messages.Contains("on").ToString());
nothing worked for now. Please help .
Edit: The answer on this site didnt work for me. I dont know where the problem is

Attempt no 1 should work fine, as long as the target string has the same casing (UPPERCASE vs lowercase). This search is case sensitive meaning it will NOT find "On", "oN" or "ON" bacause they have different casings. To make case insensitive search, you can use IndexOf instead, which takes a StringComparison parameter:
var asd2 = App.MainViewModel.Messages.Where(a => a.IndexOf("on", StringComparison.CurrentCultureIgnoreCase) >= 0);
Attempt no 2 finds the start position of the first string which matches "on" (again - case sensitive)... This doesn't make any sense really, since any string which exactly matches "on", will always start a position 0.
Attempt no 3 does the same as attempt no 1, but converts the result to a list (Where returns IEnumerable)
Attempt no 4 essentially tries to find the starting position of either "true" or "false". The Contains method will return true if the string "on" (again only exact match) is found, and that result is converted to a string and passed to the IndexOf.
UPDATE
Where returns an IEnumerable (with all the matches found). If you only need to check if "on" exists, you can use Any:
bool containsOn = App.MainViewModel.Messages.Any(a => a.IndexOf("on", StringComparison.CurrentCultureIgnoreCase) >= 0);

If you are dealing with cases and don't have an async issue, the code below works.
Check out this post
Extension method, taken from the post basicly.
public static class StringExt
{
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
return source.IndexOf(toCheck, comp) >= 0;
}
}
Note that the extension method above will find everything with "on" in it regardless of case, add or modify methods to suit your needs, makes life easier :) I personally love them!
Then for searching
// get first message with on in it
var res = App.MainViewModel.Messages.FirstOrDefault(m => m.Contains("on", StringComparison.OrdinalIgnoreCase));
// get everything with on in it
var res2 = App.MainViewModel.Messages.Where(m => m.Contains("on", StringComparison.OrdinalIgnoreCase));
Hope it helps, and was what you were after
Cheers
Stian

Sending messages as strings like this is really not ideal. Maybe have a look at this library that uses the Event aggregation pattern?
Disclaimer: I'm the author
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki

Related

Assign arguments to List

I have put together the following method:
public static bool compareTableRow(List<string> expected, int rowNumberOfElemets, IWebDriver driver)
{
List<string> actual = new List<string>
{ };
for (int i = 1; i < rowNumberOfElemets + 1; i++)
{
actual.Add(driver.FindElementHighlight
(By.XPath("//*[#id=\"nefi-content\"]/div[2]/section/div/table/tbody/tr[1]/td[" + i + "]/div/input")).GetAttribute("value"));
}
if (expected.SequenceEqual(actual)) return true;
else
return false;
}
At the moment the 'expected' List is hard-coded. What kind of method variable should I put as an input to be able to call the method and pass the strings I'm trying to compare ("bla1","123", "bla2", "etc", "etc") ?
Even with your implementation you dont need to hardcode the expected argument, it is easy to call your method like this:
compareTableRow(new List<string> {"bla1", "123", "bla2", "etc", "etc"}, 42, driver);
Alternatively, you can use params keyword (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/params):
public static bool compareTableRow(int rowNumberOfElemets, IWebDriver driver, params string[] expected)
{
...
}
and call it like you described:
compareTableRow(42, driver, "bla1", "123", "bla2", "etc", "etc");
So you have an IWebDriver, which has a notion of a number of rows. You also have an input rowNumberOfElements and a list of expected strings.
You want to check if the first rowNumberOfElements items that you can FindByElementHighlight from the IWebDriver is exactly equal to the list of expected strings.
I see several issues here:
First of all: is the order in the list of expected strings important? So should the first expected string equal the first FindByElementHighLight? According to your code the order is important.
Furthermore: is the list of expected strings long enough? Can it be longer than rowNumberElements, or is it normally exactly long enough, and can you replace the rowNumberElements with the number of elements in the expected list?
If the first element does not match, you know it's useless to check the other elements, because you already know that the return value will be false.
A generic solution
I'll use this to write it as an extension method of IWebDriver. It will be as if you ask the IWebDriver: do the first X elements of you equal the first X elements of this sequence? See extension methods demystified
static bool HasExpectedHighLights(this IWebDriver driver, ICollection<string> expected)
{
// TODO: driver == null? expected == null?
return driver.HasExpectedHighLights(expected, expected.Count);
}
static bool HasExpectedHighLights(this IWebDriver driver,
IEnumerable<string> expected, int nrOfElements)
{
// TODO: driver == null? expected == null? nrOfElements < 0?
your code goes here
}
First we'll show the usage:
List<string> expectedHighLights = ...
IWebDriver driver = ...
var isExpected = driver.HasExpectedHighLights(expectedHighLights);
But is will also work in the middle of some LINQ statement:
IEnumerable<image> images = ...
var imagesWithExpectedHighLights = images
.Where(image => image.Driver.HasExpectedHighLights(expectedHighLights))
.Slect(image => ...);
So now the code. The most important part is that we should stop as soon as you can.
static string FindElementHighLight(this IWebDriver driver, int i)
{
return driver.FindElementHighlight(By.XPath("//*[#id=\" ... etc);
}
static bool HasExpectedHighLights(this IWebDriver driver,
IEnumerable<string> expected, int nrOfElements)
{
// TODO: exception if driver == null? expected == null? nrOfElements < 0?
IEnumerable<string> actualHighLights = driver
.Select( (driver, i) => driver.FindElementHighLight(i)
.Take(nrOfElements);
// note: this has only created the enumerable.
// The sequence has not been enumerated yet
return actualHighLights.SequenceEqual(expected);
// sequence equal will stop as soon as a mismatch has been found
}
So if you find a mismatch at i == 3, then HighLight(4) is not calculated.
The nice thing is that without changing your IWebDriver, you have added functionality to it: FindElementHighLight(int).
This can be used to create the IEnumerable in SequenceEqual, which prevents having to fetch all highlights, even if you detected that the first highlight was not as expected.

C# if string contains more than 1 value

Good Morning,
In an if statement if we want to check if a string contains a value, we have :
if (string.Contains("Value1"))
{
}
How can we make the string compare with more values in an if statement without keep writing the whole statement? For example to avoid the below statement
if ((string.Contains("Value1") && (string.Contains("Value2")) && (string.Contains("Value3")))
{
}
Thank you
So, basically, you want to check if all of your values are contained in the string . Fortunately (with the help of LINQ), this can by translated almost literally into C#:
var values = new String[] {"Value1", "Value2", "Value3"};
if (values.All(v => myString.Contains(v))) {
...
}
Similarly, if you want to check if any value is contained in the string, you'd substitute All by Any.
Well, you could use LINQ:
string[] requiredContents = { "Foo", "Bar", "Baz" };
if (requiredContents.All(x => text.Contains(x))
{
...
}
Note that just like the short-circuiting && operator, All will stop as soon as it finds a value which doesn't satisfy the condition. (If you want to use Any in a similar way elsewhere, that will stop as soon as it finds a value which does satisfy the condition.)
I wouldn't bother for only a reasonably small number though. Without the extraneous brackets, it's really not that bad:
if (text.Contains("foo") && text.Contains("bar") && text.Contains("Baz"))
{
}
I would only start using the more general form if either there were genuinely quite a few values (I'd probably draw the line at about 5) or if the set of values was being passed in as a parameter, or varied in some other way.
As you need "your" string to contains all values:
var values = new String[] {"Value1", "Value2", "Value3"};
var s = yourString;
if (values.Count(v => s.Contains(v)) == values.Length) {
...
}
Is this the best solution? Probably not. Is it readable and extendable? Yes.
var matches = {"string1", "string2", "string3","string-n"};
var i = 0;
foreach(string s in matches)
{
if(mystring.Contains(s))
{
i++;
}
}
if(i == matches.Length)
{
//string contains all matches.
}
if(stringArray.Any(s => stringToCheck.Contains(s)))
If you want to ensure that it contains all the substrings, change Any to All:
if(stringArray.All(s => stringToCheck.Contains(s)))

Check if a String is combined with Several Substring in C#

Lets say I have several short string:
string[] shortStrings = new string[] {"xxx","yyy","zzz"};
(this definition can change length on array and on string too, so not a fixed one)
When a given string, I like to check if it combines with the shortStrings ONLY, how?
let say function is like bool TestStringFromShortStrings(string s)
then
TestStringFromShortStrings("xxxyyyzzz") = true;
TestStringFromShortStrings("xxxyyyxxx") = true;
TestStringFromShortStrings("xxxyyy") = true;
TestStringFromShortStrings("xxxxxx") = true;
TestStringFromShortStrings("xxxxx") = false;
TestStringFromShortStrings("xxxXyyyzzz") = false;
TestStringFromShortStrings("xxx2yyyxxx") = false;
Please suggest a memory not tense and relatively fast method.
[EIDT] What this function for?
I will personally use this function to test if a string is a combination of a PINYIN ok, some Chinese stuff. Following Chinese are same thing if you cannot read it.
检测一个字符串是否为汉语拼音(例如检测是否拼音域名)
所有的汉语拼音字符串有:
(To detect whether a string is Hanyu Pinyin (e.g. detect the phonetic domain) of the Pinyin string:)
Regex PinYin = new Regex(#"^(a|ai|an|ang|ao|ba|bai|ban|bang|bao|bei|ben|beng|bi|bian|biao|bie|bin|bing|bo|bu|ca|cai|can|cang|cao|ce|cen|ceng|cha|chai|chan|chang|chao|che|chen|cheng|chi|chong|chou|chu|chua|chuai|chuan|chuang|chui|chun|chuo|ci|cong|cou|cu|cuan|cui|cun|cuo|da|dai|dan|dang|dao|de|den|dei|deng|di|dia|dian|diao|die|ding|diu|dong|dou|du|duan|dui|dun|duo|e|ei|en|eng|er|fa|fan|fang|fei|fen|feng|fo|fou|fu|ga|gai|gan|gang|gao|ge|gei|gen|geng|gong|gou|gu|gua|guai|guan|guang|gui|gun|guo|ha|hai|han|hang|hao|he|hei|hen|heng|hong|hou|hu|hua|huai|huan|huang|hui|hun|huo|ji|jia|jian|jiang|jiao|jie|jin|jing|jiong|jiu|ju|juan|jue|jun|ka|kai|kan|kang|kao|ke|ken|keng|kong|kou|ku|kua|kuai|kuan|kuang|kui|kun|kuo|la|lai|lan|lang|lao|le|lei|leng|li|lia|lian|liang|liao|lie|lin|ling|liu|long|lou|lu|lv|luan|lue|lve|lun|luo|ma|mai|man|mang|mao|me|mei|men|meng|mi|mian|miao|mie|min|ming|miu|mo|mou|mu|na|nai|nan|nang|nao|ne|nei|nen|neng|ni|nian|niang|niao|nie|nin|ning|niu|nong|nou|nu|nv|nuan|nuo|nun|ou|pa|pai|pan|pang|pao|pei|pen|peng|pi|pian|piao|pie|pin|ping|po|pou|pu|qi|qia|qian|qiang|qiao|qie|qin|qing|qiong|qiu|qu|quan|que|qun|ran|rang|rao|re|ren|reng|ri|rong|rou|ru|ruan|rui|run|ruo|sa|sai|san|sang|sao|se|sen|seng|sha|shai|shan|shang|shao|she|shei|shen|sheng|shi|shou|shu|shua|shuai|shuan|shuang|shui|shun|shuo|si|song|sou|su|suan|sui|sun|suo|ta|tai|tan|tang|tao|te|teng|ti|tian|tiao|tie|ting|tong|tou|tu|tuan|tui|tun|tuo|wa|wai|wan|wang|wei|wen|weng|wo|wu|xi|xia|xian|xiang|xiao|xie|xin|xing|xiong|xiu|xu|xuan|xue|xun|ya|yan|yang|yao|ye|yi|yin|ying|yo|yong|you|yu|yuan|yue|yun|za|zai|zan|zang|zao|ze|zei|zen|zeng|zha|zhai|zhan|zhang|zhao|zhe|zhei|zhen|zheng|zhi|zhong|zhou|zhu|zhua|zhuai|zhuan|zhuang|zhui|zhun|zhuo|zi|zong|zou|zu|zuan|zui|zun|zuo)+$");
用下面的正则表达式方法,试过了,最简单而且效果非常好,就是有点慢:(
递归的方式对长字符串比较麻烦,容易内存溢出
(Tried it with the regular expression: it's the most simple and gives very good results, but it's a bit slow. The recursive way on the long string is too much trouble, it's too easy to overflow the stack.)
Edit: Simplified this a lot thanks to L.B and millimoose.
Regular Expressions to the rescue! Using System.Text.RegularExpressions.Regex, we get:
public static bool TestStringFromShortStrings(string checkText, string[] pieces) {
// Build the expression. Ultimate result will be
// of the form "^(xxx|yyy|zzz)+$".
var expr = "^(" +
String.Join("|", pieces.Select(Regex.Escape)) +
")+$";
// Check whether the supplied string matches the expression.
return Regex.IsMatch(checkText, expr);
}
This should be able to properly handle cases that have multiple repeated patterns of different lenghts. E.g. if you the list of possible pieces includes strings "xxx" and "xxxx".
Copy the target string to string builder. For each string in shortstring array, remove all occurences from target. If u end up in zero length string, true else false.
Edit:
This approach is not correct. Please refer to comments. Keeping this answer still here as it may look reasonably correct initially.
You could compare the start of the input string with each of the short strings. As soon as you have a match, you take the rest of the string and repeat. As soon as you have no more string left, you're done. For example:
string[] shortStrings = new string[] { "xxx", "yyy", "zzz" };
bool Test(string input)
{
if (input.Length == 0)
return true;
foreach (string shortStr in shortStrings)
{
if (input.StartsWith(shortStr))
{
if (Test(input.Substring(shortStr.Length)))
return true;
}
}
return false;
}
You might optimize this by removing the recursion, or by sorting the short strings and do a binary instead of a linear search.
Here is a non-recursive version, that uses a Stack object instead. No chance of getting a StackOverflowException:
string[] shortStrings = new string[] { "xxx", "yyy", "zzz" };
bool Test(string input)
{
Stack<string> stack = new Stack<string>();
stack.Push(input);
while (stack.Count > 0)
{
string str = stack.Pop();
if (str.Length == 0)
return true;
foreach (string shortStr in shortStrings)
{
if (str.StartsWith(shortStr))
stack.Push(str.Substring(shortStr.Length));
}
}
return false;
}

Partial Matching an ObservableCollection<string> Object

Ok let's say I have an ObservableCollection<string> object. Within this object I have a variety of strings:
SomeString01
SomeString-02
somestring-03
SOMESTRING.04
aString
I want to take an input, we'll call it pattern and store it as a string from a User interface, and do some partial matching on the ObservableCollection. I need do to partial matching on the collection, and everything is going to be case insensitive. In the end I want to these compiled into a brand new ObservableCollection. So here are some example cases:
pattern = "SoME"
// RESULTS:
SomeString01
SomeString-02
somestring-03
SOMESTRING.04
/* --- */
pattern = "-0"
// RESULTS:
SomeString-02
somestring-03
/* --- */
pattern = "ING0"
// RESULTS:
SomeString01
pattern = "s"
// RESULTS:
SomeString01
SomeString-02
somestring-03
SOMESTRING.04
aString
What is the best approach for this in a ClickOnce application?
Like Gabes answer in the comments.
but slightly more specific
.Where(x => x.IndexOf("Some",StringComparison.InvariantCultureIgnoreCase) != -1)
Ok I actually dug around more with Google, and found a better solution:
You could use IndexOf() and pass StringComparison.OrdinalIgnoreCase
string title = "STRING";
bool contains = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;
Even better is defining a new extension method for string:
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
return source.IndexOf(toCheck, comp) >= 0;
}
string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);
Contributed by: JaredPar
Source: Case insensitive 'Contains(string)'
SO now I have implemented it in my source as follows:
foreach (string source in SourceStrings)
{
// Code for some pre-reqs here
if (source.IndexOf(Pattern, StringComparison.OrdinalIgnoreCase) >= 0)
{
subset.Add(source);
}
// Finish up anything else I had to do here
}

C# Array contains partial

How to find whether a string array contains some part of string?
I have array like this
String[] stringArray = new [] { "abc#gmail.com", "cde#yahoo.com", "#gmail.com" };
string str = "coure06#gmail.com"
if (stringArray.Any(x => x.Contains(str)))
{
//this if condition is never true
}
i want to run this if block when str contains a string thats completely or part of any of array's Item.
Assuming you've got LINQ available:
bool partialMatch = stringArray.Any(x => str.Contains(x));
Even without LINQ it's easy:
bool partialMatch = Array.Exists(stringArray, x => str.Contains(x));
or using C# 2:
bool partialMatch = Array.Exists(stringArray,
delegate(string x) { return str.Contains(x)); });
If you're using C# 1 then you probably have to do it the hard way :)
If you're looking for if a particular string in your array contains just "#gmail.com" instead of "abc#gmail.com" you have a couple of options.
On the input side, there are a variety of questions here on SO which will point you in the direction you need to go to validate that your input is a valid email address.
If you can only check on the back end, I'd do something like:
emailStr = "#gmail.com";
if(str.Contains(emailStr) && str.length == emailStr.length)
{
//your processing here
}
You can also use Regex matching, but I'm not nearly familiar enough with that to tell you what pattern you'd need.
If you're looking for just anything containing "#gmail.com", Jon's answer is your best bets.

Categories

Resources