Splitting an string into a string array.? - c#

I am facing a problem while executing a sql query in C#.The sql query throws an error when the string contains more than 1000 enteries in the IN CLAUSE .The string has more than 1000 substrings each seperated by ','.
I want to split the string into string array each containing 999 strings seperated by ','.
or
How can i find the nth occurence of ',' in a string.

Pull the string from SQL server into a DataSet using a utilities code like
string strResult = String.Empty;
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = strSQL;
strResult = cmd.ExecuteScalar().ToString();
}
Get the returned string from SQL Server
Split the string on the ','
string[] strResultArr = strResult.Split(',');
then to get the nth string that is seperated by ',' (I think this is what you mean by "How can i find the nth occurence of ',' in a string." use
int n = someInt;
string nthEntry = strResultArr[someInt - 1];
I hope this helps.

You could use a regular expression and the Index property of the Match class:
// Long string of 2000 elements, seperated by ','
var s = String.Join(",", Enumerable.Range(0,2000).Select (e => e.ToString()));
// find all ',' and use '.Index' property to find the position in the string
// to find the first occurence, n has to be 0, etc. etc.
var nth_position = Regex.Matches(s, ",")[n].Index;
To create an array of strings of your requiered size, you could split your string and use LINQ's GroupBy to partition the result, and then joining the resulting groups together:
var result = s.Split(',').Select((x, i) => new {Group = i/1000, Value = x})
.GroupBy(item => item.Group, g => g.Value)
.Select(g => String.Join(",", g));
result now contains two strings, each with 1000 comma seperated elements.

How's this:
int groupSize = 1000;
string[] parts = s.Split(',');
int numGroups = parts.Length / groupSize + (parts.Length % groupSize != 0 ? 1 : 0);
List<string[]> Groups = new List<string[]>();
for (int i = 0; i < numGroups; i++)
{
Groups.Add(parts.Skip(i * groupSize).Take(groupSize).ToArray());
}

Maybe something like this:
string line = "1,2,3,4";
var splitted = line.Split(new[] {','}).Select((x, i) => new {
Element = x,
Index = i
})
.GroupBy(x => x.Index / 1000)
.Select(x => x.Select(y => y.Element).ToList())
.ToList();
After this you should just String.Join each IList<string>.

//initial string of 10000 entries divided by commas
string s = string.Join(", ", Enumerable.Range(0, 10000));
//an array of entries, from the original string
var ss = s.Split(',');
//auxiliary index
int index = 0;
//divide into groups by 1000 entries
var words = ss.GroupBy(w =>
{
try
{
return index / 1000;
}
finally
{
++index;
}
})//join groups into "words"
.Select(g => string.Join(",", g));
//print each word
foreach (var word in words)
Console.WriteLine(word);
Or you may find the indeces in the string and split it into substrings afterwards:
string s = string.Join(", ", Enumerable.Range(0, 100));
int index = 0;
var indeces =
Enumerable.Range(0, s.Length - 1).Where(i =>
{
if (s[i] == ',')
{
if (index < 9)
++index;
else
{
index = 0;
return true;
}
}
return false;
}).ToList();
Console.WriteLine(s.Substring(0, indeces[0]));
for (int i = 0; i < indeces.Count - 1; i++)
{
Console.WriteLine(s.Substring(indeces[i], indeces[i + 1] - indeces[i]));
}
However, I would think over, if it was possible to work with the entries before they are combined into one string. And probably think, if it was possible to prevent the necessity to make a query which needs that great list to pass into the IN statement.

string foo = "a,b,c";
string [] foos = foo.Split(new char [] {','});
foreach(var item in foos)
{
Console.WriteLine(item);
}

Related

Get count of unique characters between first and last letter

I'm trying to get the unique characters count that are between the first and last letter of a word. For example: if I type Yellow the expected output is Y3w, if I type People the output should be P4e and if I type Money the output should be M3y. This is what I tried:
//var strArr = wordToConvert.Split(' ');
string[] strArr = new[] { "Money","Yellow", "People" };
List<string> newsentence = new List<string>();
foreach (string word in strArr)
{
if (word.Length > 2)
{
//ignore 2-letter words
string newword = null;
int distinctCount = 0;
int k = word.Length;
int samecharcount = 0;
int count = 0;
for (int i = 1; i < k - 2; i++)
{
if (word.ElementAt(i) != word.ElementAt(i + 1))
{
count++;
}
else
{
samecharcount++;
}
}
distinctCount = count + samecharcount;
char frst = word[0];
char last = word[word.Length - 1];
newword = String.Concat(frst, distinctCount.ToString(), last);
newsentence.Add(newword);
}
else
{
newsentence.Add(word);
}
}
var result = String.Join(" ", newsentence.ToArray());
Console.WriteLine("Output: " + result);
Console.WriteLine("----------------------------------------------------");
With this code I'm getting the expect output for Yellow, but seems that is not working with People and Money. What can I do to fix this issue or also I'm wondering is maybe there is a better way to do this for example using LINQ/Regex.
Here's an implementation that uses Linq:
string[] strArr = new[]{"Money", "Yellow", "People"};
List<string> newsentence = new List<string>();
foreach (string word in strArr)
{
if (word.Length > 2)
{
// we want the first letter, the last letter, and the distinct count of everything in between
var first = word.First();
var last = word.Last();
var others = word.Skip(1).Take(word.Length - 2);
// Case sensitive
var distinct = others.Distinct();
// Case insensitive
// var distinct = others.Select(c => char.ToLowerInvariant(c)).Distinct();
string newword = first + distinct.Count().ToString() + last;
newsentence.Add(newword);
}
else
{
newsentence.Add(word);
}
}
var result = String.Join(" ", newsentence.ToArray());
Console.WriteLine(result);
Output:
M3y Y3w P4e
Note that this doesn't take account of case, so the output for FiIsSh is 4.
Maybe not the most performant, but here is another example using linq:
var words = new[] { "Money","Yellow", "People" };
var transformedWords = words.Select(Transform);
var sentence = String.Join(' ', transformedWords);
public string Transform(string input)
{
if (input.Length < 3)
{
return input;
}
var count = input.Skip(1).SkipLast(1).Distinct().Count();
return $"{input[0]}{count}{input[^1]}";
}
You can implement it with the help of Linq. e.g. (C# 8+)
private static string EncodeWord(string value) => value.Length <= 2
? value
: $"{value[0]}{value.Substring(1, value.Length - 2).Distinct().Count()}{value[^1]}";
Demo:
string[] tests = new string[] {
"Money","Yellow", "People"
};
var report = string.Join(Environment.NewLine, tests
.Select(test => $"{test} :: {EncodeWord(test)}"));
Console.Write(report);
Outcome:
Money :: M3y
Yellow :: Y3w
People :: P4e
A lot of people have put up some good solutions. I have two solutions for you: one uses LINQ and the other does not.
LINQ, Probably not much different from others
if (str.Length < 3) return str;
var midStr = str.Substring(1, str.Length - 2);
var midCount = midStr.Distinct().Count();
return string.Concat(str[0], midCount, str[str.Length - 1]);
Non-LINQ
if (str.Length < 3) return str;
var uniqueLetters = new Dictionary<char, int>();
var midStr = str.Substring(1, str.Length - 2);
foreach (var c in midStr)
{
if (!uniqueLetters.ContainsKey(c))
{
uniqueLetters.Add(c, 0);
}
}
var midCount = uniqueLetters.Keys.Count();
return string.Concat(str[0], midCount, str[str.Length - 1]);
I tested this with the following 6 strings:
Yellow
Money
Purple
Me
You
Hiiiiiiiii
Output:
LINQ: Y3w, Non-LINQ: Y3w
LINQ: M3y, Non-LINQ: M3y
LINQ: P4e, Non-LINQ: P4e
LINQ: Me, Non-LINQ: Me
LINQ: Y1u, Non-LINQ: Y1u
LINQ: H1i, Non-LINQ: H1i
Fiddle
Performance-wise I'd guess they're pretty much the same, if not identical, but I haven't run any real perf test on the two approaches. I can't imagine they'd be much different, if at all. The only real difference is that the second route expands Distinct() into what it probably does under the covers anyway (I haven't looked at the source to see if that's true, but that's a pretty common way to get a count of . And the first route is certainly less code.
I Would use Linq for that purpose:
string[] words = new string[] { "Yellow" , "People", "Money", "Sh" }; // Sh for 2 letter words (or u can insert 0 and then remove the trinary operator)
foreach (string word in words)
{
int uniqeCharsInBetween = word.Substring(1, word.Length - 2).ToCharArray().Distinct().Count();
string result = word[0] + (uniqeCharsInBetween == 0 ? string.Empty : uniqeCharsInBetween.ToString()) + word[word.Length - 1];
Console.WriteLine(result);
}

Join List of strings trailing values don't require delimiters if the right most value is null

What im trying to achieve, but cant get my head around is if i have a list of strings say:
{"test","","data","","123","44"}
this should be joined by a character:
test::data::123:44
but if the list at the end is empty dont delimiter it
{"test","","data","","",""}
should be:
test::data
{"test","","","","",""}
should be:
test
{"test","","","","","44"}
should be:
test::::44
however the list can be of varying lengths which adds another level of complexity.
Just exclude the trailing empty elements from the list Count and then Join the remaining using Take:
List<string> input = ...;
int count = input.Count;
while (count > 0 && string.IsNullOrEmpty(input[count - 1]))
count--;
var output = string.Join(":", input.Take(count));
Using the List<T> specific FindLastIndex method, it can be reduced to the following "one liner":
var output = string.Join(":",
input.Take(input.FindLastIndex(s => !string.IsNullOrEmpty(s)) + 1));
First, with your array:
test = test.Where(x => !string.IsNullOrEmpty(x)).ToArray();
where "test" is your array.
then:
string.Join("::", test);
EDIT:
If you're getting your array of strings by splitting another string, consider the following:
string[] strs = myString.split(someDelimeter, StringSplitOptions.RemoveEmptyEntries);
Start by identifying the last element you want, then slice your list and join as you normally would:
var lastElementIndex = strings.Select((s, index) => string.IsNullOrEmpty(s) ? -1 : index).Max();
var prefix = strings.Take(lastElementIndex + 1);
var result = string.Join(":", prefix);
var obj = {"test","","data","","123","44"};
var count = obj.Count;
for (var i = count - 1; i > -1; i--)
{
if (obj[i]==String.Empty) {
obj.RemoveAt(i);
}
else break;
}
var arr = obj.Split(new char[] { ','}, StringSplitOptions.RemoveEmptyEntries);
var output = arr.Join(":", arr);

How to perform word search using LINQ?

I have a list which contains the name of suppliers. Say
SuppId Supplier Name
----------------------------------
1 Aardema & Whitelaw
2 Aafedt Forde Gray
3 Whitelaw & Sears-Ewald
using following LINQ query
supplierListQuery = supplierListQuery.Where(x => x.SupplierName.Contains(SearchKey));
I can return records correctly in the following conditions,
1) If i am using search string as "Whitelaw & Sears-Ewald" it will return 3rd record.
2) If i am using "Whitelaw" or "Sears-Ewald" it will return 3rd record.
But how can i return 3rd record if i am giving search string as "Whitelaw Sears-Ewald". It always returns 0 records.
Can i use ALL to get this result, but i dont know how to use it for this particular need.
What I usually do in this situation is split the words into a collection, then perform the following:
var searchopts = SearchKey.Split(' ').ToList();
supplierListQuery = supplierListQuery
.Where(x => searchopts.Any(y=> x.SupplierName.Contains(y)));
This works for me:
IEnumerable<string> keyWords = SearchKey.Split('');
supplierListQuery = supplierListQuery
.AsParallel()
.Where
(
x => keyWords.All
(
keyword => x.SupplierName.ContainsIgnoreCase(keyword)
)
);
Thank you all for your quick responses. But the one which worked or a easy fix to handle this was timothyclifford's note on this. Like he said i alterd my answer to this
string[] filters = SearchKey.ToLower().Split(new[] { ' ' });
objSuppliersList = (from x in objSuppliersList
where filters.All(f => x.SupplierName.ToLower().Contains(f))
select x).ToList();
Now it returns the result for all my serach conditions.
Because "Whitelaw" appears in both you will get both records. Otherwise there is no dynamic way to determine you only want the last one. If you know you only have these 3 then append .Last() to get the final record.
supplierListQuery = supplierListQuery.Where(x => x.SupplierName.Contains(SearchKey.Split(' ')[0]));
You need to use some sort of string comparer to create your own simple Search Engine and then you can find strings that are most likely to be included in your result :
public static class SearchEngine
{
public static double CompareStrings(string val1, string val2)
{
if ((val1.Length == 0) || (val2.Length == 0)) return 0;
if (val1 == val2) return 100;
double maxLength = Math.Max(val1.Length, val2.Length);
double minLength = Math.Min(val1.Length, val2.Length);
int charIndex = 0;
for (int i = 0; i < minLength; i++) { if (val1.Contains(val2[i])) charIndex++; }
return Math.Round(charIndex / maxLength * 100);
}
public static List<string> Search(this string[] values, string searchKey, double threshold)
{
List<string> result = new List<string>();
for (int i = 0; i < values.Length; i++) if (CompareStrings(values[i], searchKey) > threshold) result.Add(values[i]);
return result;
}
}
Example of usage :
string[] array = { "Aardema & Whitelaw", "Aafedt Forde Gray", "Whitelaw & Sears-Ewald" };
var result = array.Search("WhitelawSears-Ewald", 80);
// Results that matches this string with 80% or more
foreach (var item in result)
{
Console.WriteLine(item);
}
Output: Whitelaw & Sears-Ewald
If you want an easy (not very handy) solution,
var result = supplierListQuery
.Select(x => normalize(x.SupplierName))
.Where(x => x.Contains(normalize(SearchKey)));
string normalize(string inputStr)
{
string retVal = inputStr.Replace("&", "");
while (retVal.IndexOf(" ") >= 0)
{
retVal = retVal.Replace(" ", " ");
}
return retVal;
}

Linq: splitting a string length and storing the result using a list

I am new to Linq and am re-factoring some of my old code over to Linq. I have a small problem that I solved using the foreach loop that stores each 250 char's to a list. It would be good to rewrite this using linq, but it seems to not be working. Can someone shed a little light on this?
Code to be refactored:
string comment = "This can be however long but needs to be broken down into 250 chars and stored in a list";
char[] charList = comment.ToCharArray();
int charCount = charList.Count() / 250;
List<string> charCollection = new List<string>();
string tempStr = string.Empty;
foreach (char x in charList){
if (tempStr.Count() != 250){
tempStr = tempStr + x.ToString();
}
else {
if (tempStr.Count() <= 250) {
charCollection.Add(tempStr);
tempStr = "";
}
}
Not so good attempt with Linq:
IEnumerable<string> charCat = System.Linq.Enumerable.Where(comment, n => n.ToString().Length() => 250);
Using LINQ:
List<string> chunks =
comment
// for each character in the string, project a new item containing the
// character itself and its index in the string
.Select((ch, idx) => new { Character = ch, Index = idx })
// Group the characters by their "divisibility" by 250
.GroupBy(
item => item.Index / 250,
item => item.Character,
// Make the result of the GroupBy a string of the grouped characters
(idx, grp) => new string(grp.ToArray()))
.ToList();
See the documentation for .GroupBy and .Select for more information on those methods.
In general, I think the 101 LINQ samples on MSDN are a great resource for learning LINQ.

Split string with Pipe for a chunk in simplest way?

Got a string let say
string mystring = "A\nB\nC\nD\nE\nF\nG\n"
want to convert it with | for chunk of 5
string Converted string ="ABCDE|FG"
Any one liner solution..
I am going this way
private void TweakInputLines(string InputData)
{
List<string> lstInput = new List<string>();
if (!string.IsNullOrEmpty(InputData))
{
lstInput = InputData.Split('\n').ToList();
if (lstInput.Count > 4)
{
}
}
}
Try this one liner
string mystring = "A\nB\nC\nD\nE\nF\nG\n";
var result = Regex.Replace(mystring.Replace("\n", ""), ".{5}", "$0|");
Here is the demo.
General solution (preserving variable length lines):
string input = "A\nBC\nDEF\nG\nH\nI\nJKL\nMN\nO\nP\nQR\nS";
string output = string.Join("|", input.Split('\n')
.Select((s, i) => new { s, i })
.GroupBy(p => p.i / 5)
.Select(g => string.Join("", g.Select(p => p.s))));
Output:
ABCDEFGH|IJKLMNOP|QRS
Update
If you use .Net 3.5, then you need to add .ToArray() calls in string.Join() methods.
string input = "A\nBC\nDEF\nG\nH\nI\nJKL\nMN\nO\nP\nQR\nS";
string output = string.Join("|", input.Split('\n')
.Select((s, i) => new { s, i })
.GroupBy(p => p.i / 5)
.Select(g => string.Join("", g.Select(p => p.s).ToArray()))
.ToArray());
Update 2
Another option is to use slightly modified solution by #SriramSakthivel
string input = "A\nBC\nDEF\nG\nH\nI\nJKL\nMN\nO\nP\nQR\nS";
string output = Regex.Replace(input, #"((?:.*\n){4}.*)\n", "$1|").Replace("\n", "");
Simple code is
private void TweakInputLines(string InputData)
{
List<string> lstInput = new List<string>();
var returnstring = "";
if (!string.IsNullOrEmpty(InputData))
{
lstInput = InputData.Split('\n').ToList();
if (lstInput.Count > 9999)
{
int counter = 0;
foreach (var eachcharitem in lstInput)
{
counter++;
returnstring = returnstring + eachcharitem;
if (counter == 5)
{
returnstring = returnstring + "|";
counter = 0;
}
}
}
}
}
Another solution with the use of Linq - its more or less a "one-liner":
string mystring = "A\nB\nC\nD\nE\nF\nG\n";
var str = mystring
.Select((value, index) => new { Index = index, Value = value }) // insert Index
.GroupBy(i => (int)(i.Index / 5)) // group by index / 5
.Select(value => String.Join("",value.Select(temp => temp.Value))) // create string out of grouped chars
.Aggregate((a,b) => a + "|" + b); // create one string out of splitted chars
// and join the "|"-string in between

Categories