I have a comma separated string stored in database.
E.g.: record1 = "1,3,5,7,9,10" and record2 = "4,5,10"
And I have a given information, E.g.: 1.
I have to select the record using LINQ that contains the given info of 1.
The result returned should be record1.
If I were to use .contains() solely, it's not accurate as record2 will be returned as well.
How can I achieve that? Is it possible to achieve that in a single LINQ query?
Thanks for advise !
With a single LINQ-to-objects query:
string[] records = new[] { record1, record2 };
string record = records.FirstOrDefault(r => r.Split(',').Any(s => s == "1"));
Demo
First of all I would like to mention what #Tim Schmelter said -
Have you noticed already that the real problem is your creepy
datamodel? Use a table with real records instead of a column with a
comma separated string.
It is not a good practice to use a datamodel where you need string split match. Because it leads to inefficient systems and not to mention slow queries. But yet, if you really need a solution why not try this -.
There are four occasions where you will get a match,
A prefix match - starting with
Inner Match - contains with
Suffix Match - ends with
The only match - only one item and this is it
considering the scenario I am suggesting the solution below -
s is the value looking for say "1"
string prefixMatch = s + ",";
string suffixMatch = "," + s;
string innerMatch = "," + s + ",";
string record = <dbRecords>.FirstOrDefault(r=> r.StartsWith(prefixMatch) ||
r.Contains(innerMatch) || r.EndsWith(suffixMatch) ||
(!r.Contains(",") && r == s));
The reason for such a detailed query is to keep your memory utilisation less and letting the SQL query do the hard work of finding the results because this query will support LINQ-to-SQL conversion.
If i understand you correctly, you need as result record that contains "1". So you can use:
private bool GerRecord(string record)
{
string[] arr=record.Split(',');
return arr.Contains("1");
}
Instead of searching 1 you can try 1,(1 and comma combined) for searching in Contains in linQ
Related
I've been working on trying to get this string split in a couple different places which I managed to get to work, except if the name had a forward-slash in it, it would throw all of the groups off completely.
The string:
123.45.678.90:00000/98765432109876541/[CLAN]PlayerName joined [windows/12345678901234567]
I essentially need the following:
IP group: 123.45.678.90:00000 (without the following /)
id group: 98765432109876541
name group: [CLAN]PlayerName
id1 group: 12345678901234567
The text "joined" also has to be there. However windows does not.
Here is what I have so far:
(?<ip>.*)\/(?<id>.*)\/(.*\/)?(?<name1>.*)( joined.*)\[(.*\/)?(?<id1>.*)\]
This works like a charm unless the player name contains a "/". How would I go about escaping that?
Any help with this would be much appreciated!
Since you tag your question with C# and Regex and not only Regex, I will propose an alternative. I am not sure if it will more efficient or not. I find it easiest to read and to debug if you simply use String.Split():
Demo
public void Main()
{
string input = "123.45.678.90:00000/98765432109876541/[CLAN]Player/Na/me joined [windows/12345678901234567]";
// we want "123.45.678.90:00000/98765432109876541/[CLAN]Player/Na/me joined" and "12345678901234567]"
// Also, you can remove " joined" by adding it before " [windows/"
var content = input.Split(new string[]{" [windows/"}, StringSplitOptions.None);
// we want ip + groupId + everything else
var tab = content[0].Split('/');
var ip = tab[0];
var groupId = tab[1];
var groupName = String.Join("/", tab.Skip(2)); // merge everything else. We use Linq to skip ip and groupId
var groupId1 = RemoveLast(content[1]); // cut the trailing ']'
Console.WriteLine(groupName);
}
private static string RemoveLast(string s)
{
return s.Remove(s.Length - 1);
}
Output:
[CLAN]Player/Na/me joined
If you are using a class for ip, groupId, etc. and I guess you do, just put everything in it with a constructor which accept a string as parameter.
You shouldn't be using greedy quanitifiers (*) with an open character such as .. It won't work as intended and will result in a lot of backtracking.
This is slightly more efficient, but not overly strict:
^(?<ip>[^\/\n]+)\/(?<id>[^\/]+)\/(?<name1>\S+)\D+(?<id1>\d+)]$
Regex demo
You basically needs to use non greedy selectors (*?). Try this:
(?<ip>.*?)\/(?<id>.*?)\/(?<name1>.*?)( joined )\[(.*?\/)?(?<id1>.*?)\]
I am trying to split this string
string s = "sn DC0000002; mac 00:0c; uuid 564d6ae4-979";
I need to get these values from above string "DC0000002" , "00:0c" , "564d6ae4-979"
For this I have tried below query but not able to able to get last two values I mean these two values ("00:0c" , "564d6ae4-979")
Below is the query for splitting
List<string> decryptedList = new List<string>();
decryptedList = decodePP.Split(';').Select(x => x.Split(' ')[1]).ToList();
orgSNo = decryptedList[0]; //Output - DC0000002
orgMacID = decryptedList[1];// output - mac // this is wrong need to get value
orgUUID = decryptedList[2]; //output - uuid // this is also wrong
Would anyone please help on this query how extract values from the above string using LINQ query in a single shot?
Just trim substrings which you get after first split:
decodePP.Split(';').Select(x => x.Trim().Split(' ')[1]).ToList();
You get incorrect results, because first split gives you
[ "sn DC0000002", " mac 00:0c", " uuid 564d6ae4-979" ]
As you can see, items except first one have leading whitespace.
Alternative solution - you can use StringSplitOptions.RemoveEmptyEntries parameter to skip empty substrings
str.Split(';')
.Select(x => x.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries)[1])
.ToList()
Why do you need to use Linq. The string split would seem to do the trick?
string[] keyValuePairs = s.Split(';');
foreach(string pair.Trim() in keyValuePairs)
{
string key = pair.Split(' ')[0].Trim();
string value = pair.Split(' ')[1].Trim();
}
That's only a stab at the code - it may not compile, but you get the idea?
You could use the TrimStart() function in your linq statement like:
decryptedList = decodePP.Split(';').Select(x => x.TrimStart().Split(' ')[1]).ToList();
I have probably spent about 500 hours Googling this and reading MSDN documentation and it still refuses to work the way I want.
I can sort by name for files like this:
01.png
02.png
03.png
04.png
I.e. all the same file length.
The second there is a file with a longer file length everything goes to hell.
For example in the sequence:
1.png
2.png
3.png
4.png
5.png
10.png
11.png
It reads:
1.png, 2.png then 10.png, 11.png
I don't want this.
My Code:
DirectoryInfo di = new DirectoryInfo(directoryLoc);
FileSystemInfo[] files = di.GetFileSystemInfos("*." + fileExtension);
Array.Sort<FileSystemInfo>(files, new Comparison<FileSystemInfo>(compareFiles));
foreach (FileInfo fri in files)
{
fri.MoveTo(directoryLoc + "\\" + prefix + "{" + operationNumber.ToString() + "}" + (i - 1).ToString("D10") +
"." + fileExtension);
i--;
x++;
progressPB.Value = (x / fileCount) * 100;
}
// compare by file name
int compareFiles(FileSystemInfo a, FileSystemInfo b)
{
// return a.LastWriteTime.CompareTo(b.LastWriteTime);
return a.Name.CompareTo(b.Name);
}
It's not a matter of the file length particularly - it's a matter of the names being compared in lexicographic order.
It sounds like in this particular case you want to get the name without the extension, try to parse it as an integer, and compare the two names that way - you could fall back to lexicographic ordering if that fails.
Of course, that won't work if you have "debug1.png,debug2.png,...debug10.png"...you'd need a more sophisticated algorithm in that case.
You're comparing the names as strings, even though (I'm assuming) you want them sorted by number.
This is a well-known problem where "10" comes before "9" because the first character in 10 (1) is less than the first character in 9.
If you know that the files will all consist of numbered names, you can modify your custom sort routine to convert the names to integers and sort them appropriately.
Your code is correct and working as expected, just the sort is performed alphabetically, not numerically.
For instance, the strings "1", "10", "2" are in alphabetical order. Instead if you know your filenames are always just a number plus ".png" you can do the sort numerically. For instance, something like this:
int compareFiles(FileSystemInfo a, FileSystemInfo b)
{
// Given an input 10.png, parses the filename as integer to return 10
int first = int.Parse(Path.GetFileNameWithoutExtension(a.Name));
int second = int.Parse(Path.GetFileNameWithoutExtension(b.Name));
// Performs the comparison on the integer part of the filename
return first.CompareTo(second);
}
I ran into this same issue, but instead of sorting the list myself, I changed the filename by using 6 digit '0' padded key.
My list now looks like this:
000001.jpg
000002.jpg
000003.jpg
...
000010.jpg
But, if you can't change the filenames, you're going to have to implement your own sorting routine to deal with the alpha sort.
How about a bit of linq and regex to fix the ordering?
var orderedFileSysInfos =
new DirectoryInfo(directoryloc)
.GetFileSystemInfos("*." + fileExtension)
//regex below grabs the first bunch of consecutive digits in file name
//you might want something different
.Select(fsi => new{fsi, match = Regex.Match(fsi.Name, #"\d+")})
//filter away names without digits
.Where(x => x.match.Success)
//parse the digits to int
.Select(x => new {x.fsi, order = int.Parse(x.match.Value)})
//use this value to perform ordering
.OrderBy(x => x.order)
//select original FileSystemInfo
.Select(x => x.fsi)
//.ToArray() //maybe?
I have the following string which i would like to retrieve some values from:
============================
Control 127232:
map #;-
============================
Control 127235:
map $;NULL
============================
Control 127236:
I want to take only the Control . Hence is there a way to retrieve from that string above into an array containing like [127232, 127235, 127236]?
One way of achieving this is with regular expressions, which does introduce some complexity but will give the answer you want with a little LINQ for good measure.
Start with a regular expression to capture, within a group, the data you want:
var regex = new Regex(#"Control\s+(\d+):");
This will look for the literal string "Control" followed by one or more whitespace characters, followed by one or more numbers (within a capture group) followed by a literal string ":".
Then capture matches from your input using the regular expression defined above:
var matches = regex.Matches(inputString);
Then, using a bit of LINQ you can turn this to an array
var arr = matches.OfType<Match>()
.Select(m => long.Parse(m.Groups[1].Value))
.ToArray();
now arr is an array of long's containing just the numbers.
Live example here: http://rextester.com/rundotnet?code=ZCMH97137
try this (assuming your string is named s and each line is made with \n):
List<string> ret = new List<string>();
foreach (string t in s.Split('\n').Where(p => p.StartsWith("Control")))
ret.Add(t.Replace("Control ", "").Replace(":", ""));
ret.Add(...) part is not elegant, but works...
EDITED:
If you want an array use string[] arr = ret.ToArray();
SYNOPSYS:
I see you're really a newbie, so I try to explain:
s.Split('\n') creates a string[] (every line in your string)
.Where(...) part extracts from the array only strings starting with Control
foreach part navigates through returned array taking one string at a time
t.Replace(..) cuts unwanted string out
ret.Add(...) finally adds searched items into returning list
Off the top of my head try this (it's quick and dirty), assuming the text you want to search is in the variable 'text':
List<string> numbers = System.Text.RegularExpressions.Regex.Split(text, "[^\\d+]").ToList();
numbers.RemoveAll(item => item == "");
The first line splits out all the numbers into separate items in a list, it also splits out lots of empty strings, the second line removes the empty strings leaving you with a list of the three numbers. if you want to convert that back to an array just add the following line to the end:
var numberArray = numbers.ToArray();
Yes, the way exists. I can't recall a simple way for It, but string is to be parsed for extracting this values. Algorithm of it is next:
Find a word "Control" in string and its end
Find a group of digits after the word
Extract number by int.parse or TryParse
If not the end of the string - goto to step one
realizing of this algorithm is almost primitive..)
This is simplest implementation (your string is str):
int i, number, index = 0;
while ((index = str.IndexOf(':', index)) != -1)
{
i = index - 1;
while (i >= 0 && char.IsDigit(str[i])) i--;
if (++i < index)
{
number = int.Parse(str.Substring(i, index - i));
Console.WriteLine("Number: " + number);
}
index ++;
}
Using LINQ for such a little operation is doubtful.
I have list of strings. I want to convert each element of it to single quoted string (i.e "ABC" --> 'ABC'), How to do this in .net.
Thanks,
Omkar
Linq can help here.
var newList = oldList.Select(c => c.Replace("\"", "'"));
This is already well answered. However, I have the hunch that you are taking a list of strings in C#, then trying to build an SQL expression for use in IN statements, e.g.:
SELECT * FROM table WHERE name IN ('John','Mary','Peter')
In that case, you'd need to join the strings together, as well as protect from code injection attacks by doubling any single-quote characters.
StringBuilder sb = new StringBuilder();
foreach (string entry in list) {
if (sb.Length > 0) sb.Append(",");
sb.Append("\'" + entry.Replace("'","''") + "\'");
}
string expr = sb.ToString();
You'd also need to handle the special case when the list is empty because IN () is not a valid syntax for SQL.
If this is not what you want, just ignore me. :-)
I assume you have regular strings s to 's' (quoted string) and you wanted a List<> to be converted.
List<string> stringList = new List<string>();
//Fill the list with strings here.
var query = from str in stringList
select string.Format("\'{0}\'", str);
List<string> quotedList = query.ToList<string>();
If you want to replace all double with single quotes, simply do this:
myString = myString.Replace( "\"", "'" );
However, note that ' is not a valid string delimiter in C#, so you can't have the string 'ABC', but you can have the string "'ABC'" that contains the text 'ABC'
EDIT
When looking at Geoff's answer, I saw that you wanted a list. In that case, his answer is almost correct- Try this variant instead:
var convertedList = myStringList.Select(s => s = s.Replace("\"", "'").ToList();