How to use Inner Parallel loop within Parallel.Foreach c#? - c#

I am trying to optimize my code, I want to call Parallel.For inside a Parallel.ForEach(). I am not sure how can I do so. If I do see that the results are not correct. My code reverses the word within a sentence.
changed that for loop and it works.
for (int i = word.Length - 1; i >= 0; i--)
Here is my original code which fails.
public string Test()
{
string s = "Hello how are you";
if (s.Length > 0)
{
StringBuilder reverseS = new StringBuilder(s.Length);
string[] words = s.Split(' ');
Parallel.ForEach(words, word =>
{
StringBuilder builder = new StringBuilder(word.Length);
Parallel.For(0, word.Length - 1, i =>
//for (int i = word.Length - 1; i >= 0; i--)
{
builder.Append(word[i]);
});
reverseS.Append(builder);
reverseS.Append(" ");
});
return reverseS.ToString();
}
else
{
return "";
}
}
olleH woh era uoy

I see you have to reverse the chars but keep word positions. I don't know how good is the code below in comparison to your solution, so you can have some performance tests.
The idea is to reverse the words in array in the main thread and start a parallel one if we encounter a very long word.
private void Reverse()
{
const int extremelyLongWordLength = 100000;
var tasks = new List<Task>();
var wordStart = 0;
var arr = "Hello how are you".ToCharArray();
for (var i = 0; i < arr.Length; i++)
{
if (arr[i] == ' ')
{
var wordEnd = i - 1;
if (wordEnd - wordStart >= extremelyLongWordLength)
{
tasks.Add(ReverseWordAsTask(arr, wordStart, wordEnd));
}
else
{
ReverseWord(arr, wordStart, wordEnd);
}
wordStart = i + 1;
}
}
if (wordStart != arr.Length - 1)
{
if (arr.Length - 1 - wordStart > extremelyLongWordLength)
{
tasks.Add(ReverseWordAsTask(arr, wordStart, arr.Length - 1));
}
else
{
ReverseWord(arr, wordStart, arr.Length - 1);
}
}
Task.WaitAll(tasks.ToArray());
var modifiedString = new string(arr);
}
private static Task ReverseWordAsTask(char[] arr, int start, int end)
{
return Task.Run(() =>
{
var halfWordIndex = start + (end - start) / 2;
for (var i = start; i < halfWordIndex; i++)
{
var temp = arr[i];
var opposite = end - (i - start);
arr[i] = arr[opposite];
arr[opposite] = temp;
}
});
}
private static void ReverseWord(char[] arr, int start, int end)
{
var halfWordIndex = start + (end - start) / 2;
for (var i = start; i < halfWordIndex; i++)
{
var temp = arr[i];
var opposite = end - (i - start);
arr[i] = arr[opposite];
arr[opposite] = temp;
}
}

Related

Finding list of unique subsets of a given list of integers [duplicate]

This question already has answers here:
How to generate all subsets of a given size?
(5 answers)
Closed 6 years ago.
Looking for an efficient way to determine all unique subsets of a list of integers.
Say I have a List of integers containing 340 integers. I want a List of all possible subsets (of 5 elements each). All supplied integers will be unique, and the result should not duplicate any element in it's subset. An example given an input of 1,2,3,4,5,6,7,8,9 I am looking for an output of
1,2,3,4,5
1,2,3,4,6
1,2,3,4,7
1,2,3,4,8
1,2,3,4,9
1,2,3,5,6
1,2,3,5,7
...
I must do this in CSharp. can this be done in LINQ?
I have answered a several combinatorial questions, and everywhere I use a variation of a non recursive allocation free algorithm. For this case, it looks like this:
public static class Algorithms
{
public static IEnumerable<T[]> GetCombinations<T>(this T[] input, int N)
{
var result = new T[N];
var indices = new int[N];
for (int pos = 0, index = 0; ;)
{
for (; pos < N; pos++, index++)
{
indices[pos] = index;
result[pos] = input[index];
}
yield return result;
do
{
if (pos == 0) yield break;
index = indices[--pos] + 1;
}
while (index > input.Length - N + pos);
}
}
}
As in the other implementations, the method yields one and the same internal buffer, which is useful when you need just to iterate and process the resulting set once. If you need to store the combinations, then you need to clone the returned array before storing it. Here is a sample usage like in your scenario:
var input = Enumerable.Range(1, 20);
var result = input
.Distinct()
.ToArray()
.GetCombinations(5)
.Select(c => (int[])c.Clone())
.ToList();
UPDATE: The GetCombinations method basically emulates N nested loops like this (in pseudo code):
for (int i0 = 0; i0 <= input.Length - N; i0++)
for (int i1 = i0 + 1; i1 <= input.Length - N + 1; i1++)
for (int i2 = i1 + 1; i2 <= input.Length - N + 2; i2++)
...
for (int iN-1 = iN-2 + 1; iN-1 <= input.Length - 1; iN-1++)
yield { input[i0], input[i1], input[i2], ..., input[iN-1] }
In case of a tractable set of 9 elements (or max 25-30) and subset of 5, the code could be based on a recursive function
static void Main(string[] args)
{
foreach (var item in ListPerm())
{
Console.WriteLine(String.Join(",", item));
}
Console.Read();
}
private static List<List<int>> ListPerm(HashSet<int> mySet = null, int deep = 5)
{
if (mySet == null)
{
mySet = initSet(8);
}
if (deep <= 0)
{
return Enumerable.Empty<List<int>>().ToList();
}
List<List<int>> all = new List<List<int>>();
for (int i = 0; i < mySet.Count - deep + 1; i++)
{
if (deep == 1)
{
var list = new List<int>() { mySet.ElementAt(i) };
all.Add(list);
}
foreach (var item in ListPerm(new HashSet<int>(mySet.Skip(i+1)), deep - 1))
{
var list = new List<int>() { mySet.ElementAt(i) };
list.AddRange(item);
all.Add(list);
}
}
return all;
}
private static HashSet<int> initSet(int lenght)
{
HashSet<int> ret = new HashSet<int>();
for (int i = 0; i < lenght; i++)
{
ret.Add(i * 1 + 1); // just an example...
};
return ret;
}
Reengineering
Now, let me optimize the above code into a more performant function, that takes 3.2 seconds to get the combinations of 8 integers out of 30 on my standard laptop.
private static int[][] ListPerm(int[] mySet, int deep)
{
var all = new List<int[]>();
if (deep == 1)
{
return mySet.Select(x => new int[] { x }).ToArray();
}
else
{
var mySubSet = new int[mySet.Length - 1];
Array.Copy(mySet, 1, mySubSet, 0, mySubSet.Length);
var perm1st = ListPerm(mySubSet, deep - 1);
for (int i = 0; i < mySet.Length - deep + 1; i++)
{
var permn = perm1st.Select(x =>
{
var z = new int[x.Length + 1];
z[0] = mySet[i];
x.CopyTo(z, 1);
return z;
}
);
all.AddRange(permn);
int start = Array.FindIndex(perm1st, item => item[0] != mySet[i + 1]);
if (start > 0)
{
var temp_cpy = new int[perm1st.Length - start][];
Array.Copy(perm1st, start, temp_cpy, 0, temp_cpy.Length);
perm1st = temp_cpy;
}
}
}
return all.ToArray();
}
Benchmark
Here it is a comparison of Ivan's, my and the community wiki algorithms for the combinations of 5 ints in 20.
Results
wiki perm: 00:00:00.0950055
writing wiki perm: 00:00:00.0460026
Ivan perm: 00:00:00.0400023
writing Ivan perm: 00:00:00.0260015
my perm: 00:00:00.0110006
writing my perm: 00:00:00.0300017
Test Code
var input = Enumerable.Range(1, 20);
int deep = 5;
var start = DateTime.Now;
var wiki = Algorithms.Combinations(input, deep).ToArray();
Console.WriteLine("wiki perm: {0}", DateTime.Now - start);
start = DateTime.Now;
StreamWriter sw0 = new StreamWriter(#"C:\dev\SO\Algo\perm0.txt", false);
foreach (var item in wiki)
{
sw0.WriteLine(String.Join(",", item));
}
sw0.Close();
Console.WriteLine("writing wiki perm: {0}", DateTime.Now - start);
start = DateTime.Now;
start = DateTime.Now;
var result = input
.Distinct()
.ToArray()
.GetCombinations(deep)
.Select(c => (int[])c.Clone())
.ToList();
Console.WriteLine("Ivan perm: {0}", DateTime.Now - start);
start = DateTime.Now;
StreamWriter sw1 = new StreamWriter(#"C:\dev\SO\Algo\perm1.txt", false);
foreach (var item in result)
{
sw1.WriteLine(String.Join(",", item));
}
sw1.Close();
Console.WriteLine("writing Ivan perm: {0}", DateTime.Now - start);
start = DateTime.Now;
var myPerm = ListPermSO(input.ToArray(), deep);
Console.WriteLine("my perm: {0}", DateTime.Now - start);
start = DateTime.Now;
StreamWriter sw2 = new StreamWriter(#"C:\dev\SO\Algo\perm2.txt", false);
foreach (var item in myPerm)
{
sw2.WriteLine(String.Join(",", item));
}
sw2.Close();
Console.WriteLine("writing my perm: {0}", DateTime.Now - start);
Console.Read();

Index Of Longest Run C#

I am trying to solve this question:
Write a function that finds the zero-based index of the longest run in a string. A run is a consecutive sequence of the same character. If there is more than one run with the same length, return the index of the first one.
For example, IndexOfLongestRun("abbcccddddcccbba") should return 6 as the longest run is dddd and it first appears on index 6.
Following what i have done:
private static int IndexOfLongestRun(string str)
{
char[] array1 = str.ToCharArray();
//Array.Sort(array1);
Comparer comparer = new Comparer();
int counter =1;
int maxCount = 0;
int idenxOf = 0;
for (int i =0; i<array1.Length-1 ; i++)
{
if (comparer.Compare(array1[i],array1[i+1]) == 0)
{
counter++;
}
else {
if(maxCount < counter)
{
maxCount = counter;
idenxOf = i - counter + 1;
}
counter = 1;
}
}
return idenxOf ;
}
}
public class Comparer : IComparer<char>
{
public int Compare(char firstChar, char nextChar)
{
return firstChar.CompareTo(nextChar);
}
}
The problem is that when i get to the last index for example "abbccaaaaaaaaaa"
which is a in this case, and when i=14 (taking this string as example) and when i<array1.Length-1 statment is false, the for loop jumps directrly to return indexOf; and return the wrong index, I am trying to find out how to push the forloop to continue the implementation so idenxOf could be changed to the right index. Any help please?
You could check whether a new best score is achieved for each iteration when current == previous. Minimally slower, but it allows you to write shorter code by omitting an extra check after the loop:
int IndexOfLongestRun(string input)
{
int bestIndex = 0, bestScore = 0, currIndex = 0;
for (var i = 0; i < input.Length; ++i)
{
if (input[i] == input[currIndex])
{
if (bestScore < i - currIndex)
{
bestIndex = currIndex;
bestScore = i - currIndex;
}
}
else
{
currIndex = i;
}
}
return bestIndex;
}
Promote the loop variable i to method scope and repeat the conditional block if (maxCount < counter) { ... } right after the loop exit. Thus, it executes one more time after the loop completes
private static int IndexOfLongestRun(string str)
{
char[] array1 = str.ToCharArray();
//Array.Sort(array1);
Comparer comparer = new Comparer();
int counter = 1;
int maxCount = 0;
int idenxOf = 0;
int i;
for (i = 0; i < array1.Length - 1; i++)
{
if (comparer.Compare(array1[i], array1[i + 1]) == 0)
{
counter++;
}
else
{
if (maxCount < counter)
{
maxCount = counter;
idenxOf = i - counter + 1;
}
counter = 1;
}
}
if (maxCount < counter)
{
maxCount = counter;
idenxOf = i - counter + 1;
}
return idenxOf;
}
As usual late, but joining the party. A natural classic algorithm:
static int IndexOfLongestRun(string input)
{
int longestRunStart = -1, longestRunLength = 0;
for (int i = 0; i < input.Length; )
{
var runValue = input[i];
int runStart = i;
while (++i < input.Length && input[i] == runValue) { }
int runLength = i - runStart;
if (longestRunLength < runLength)
{
longestRunStart = runStart;
longestRunLength = runLength;
}
}
return longestRunStart;
}
At the end you have both longest run index and length.
public static int IndexOfLongestRun(string str)
{
var longestRunCount = 1;
var longestRunIndex = 0;
var isNew = false;
var dic = new Dictionary<int, int>();
for (var i = 0; i < str.Length - 1; i++)
{
if (str[i] == str[i + 1])
{
if (isNew) longestRunIndex = i;
longestRunCount++;
isNew = false;
}
else
{
isNew = true;
dic.Add(longestRunIndex, longestRunCount);
longestRunIndex = 0;
longestRunCount = 1;
}
}
return dic.OrderByDescending(x => x.Value).First().Key;
}
This will return -1 if the string is empty and you have the flexibility of returning the index and the count depending on your specification.
string myStr = "aaaabbbbccccccccccccdeeeeeeeee";
var longestIndexStart = -1;
var longestCount = 0;
var currentCount = 1;
var currentIndexStart = 0;
for (var idx = 1; idx < myStr.Length; idx++)
{
if (myStr[idx] == myStr[currentIndexStart])
currentCount++;
else
{
if (currentCount > longestCount)
{
longestIndexStart = currentIndexStart;
longestCount = currentCount;
}
currentIndexStart = idx;
currentCount = 1;
}
}
return longestIndexStart;
The accepted answer from Kvam works great for small strings, but as the length approaches 100,000 characters (and perhaps this isn't needed), its efficiency wains.
public static int IndexOfLongestRun(string str)
{
Dictionary<string, int> letterCount = new Dictionary<string, int>();
for (int i = 0; i < str.Length; i++)
{
string c = str.Substring(i, 1);
if (letterCount.ContainsKey(c))
letterCount[c]++;
else
letterCount.Add(c, 1);
}
return letterCount.Values.Max();
}
This solution is twice as fast as Kvam's with large strings. There are, perhaps, other optimizations.

C# printing and skipping a certain number of characters

Ok, here's the problem that I have: using C# I want to format a string by printing out a certain number of characters, then skipping a certain number of characters and then again print, skip.
For example: I want to print 3 characters by skipping the next 2.
So this:
ABCDEFGHIJKL
would become this:
ABCFGHKL
I have only made that it could skip every 2,3,4 and so on characters and I couldn't think of how to approach this further.
Here is so far what I have
string text;
int print = 3;
int skip = 2;
StreamReader file = new StreamReader(#"c:\test.txt");
while ((text = file.Readtext()) != null)
{
string[] stringArray = new string[text.Length];
char ch;
for (int i = 0; i < text.Length; i++)
{
ch = text[i];
stringArray[i] = ch.ToString();
}
for (int i = 0; i < stringArray.Length; i+=skip)
{
Console.Write(stringArray[i]);
}
}
Thanks.
Thank you guys for various great solutions, I really appreciate your help! Thanks!
int take = 3;
int skip = 2;
string s = "ABCDEFGHIJKL";
var newstr = String.Join("", s.Where((c,i) => i % (skip + take) < take));
EDIT
Here are my test results....
int take = 3;
int skip = 2;
string s = String.Join("",Enumerable.Repeat("0123456789", 200));
var t1 = Measure(10000, () => { var newstr = String.Join("", s.Where((c, i) => i % (skip + take) < take)); });
var t2 = Measure(10000, () => { var newstr = new string(s.Where((c, i) => i % (skip + take) < take).ToArray()); });
var t3 = Measure(10000, () => { var newstr = GetString(s, take, skip); });
long Measure(int n,Action action)
{
action(); //JIT???
var sw = Stopwatch.StartNew();
for (int i = 0; i < n; i++)
{
action();
}
return sw.ElapsedMilliseconds;
}
OUTPUT:
1665 ms. (String.Join)
1154 ms. (new string())
7457 ms. (Sayse's GetString)
EDIT 2
Modifying Sayse's answer as below gives the fastest result among the codes i tested. (311 ms)
public string GetString(string s, int substringLen, int skipCount)
{
StringBuilder newString = new StringBuilder(s.Length);
for (int i = 0; i < s.Length; i += skipCount)
{
for (int j = 0; j < substringLen && i < s.Length; j++)
{
newString.Append(s[i++]);
}
}
return newString.ToString();
}
I like I4V's answer more but heres one way to achieve this
public string GetString(string s, int substringLen, int skipCount)
{
string newString = "";
for (int i = 0; i < s.Length; i += skipCount)
{
for (int j = 0; j < substringLen && i < s.Length; j++)
{
newString += s[i++];
}
}
return newString;
}
Edit Benchmark stated my way was faster
var newStr2 = new Program().GetString(a, take, skip);
var newstr = String.Join("", a.Where((c, i) => i % (skip + take) < take));
sw.Start();
for (int i = 0; i < 1000000; i++)
{
newStr2 = new Program().GetString(a, take, skip);
}
sw.Stop();
Console.WriteLine("my way: " + sw.Elapsed.ToString());
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000; i++)
{
newstr = String.Join("", a.Where((c, iv) => iv % (skip + take) < take));
}
sw.Stop();
Console.WriteLine("I4V way: " + sw.Elapsed.ToString());
Output
my way: 00:00:00.7634927
I4V way: 00:00:01.0183307
int print = 3;
int skip = 2;
Boolean isPrintState = true;
int statePosition = 0;
StringBuilder Sb = new StringBuilder();
using (TextReader reader = new StreamReader(#"c:\test.txt")) {
while (true) {
int Ch = reader.Read();
if (Ch < 0)
break;
statePosition += 1;
if ((isPrintState && (statePosition > print)) || (!isPrintState && (statePosition > skip))) {
statePosition = 1;
isPrintState = !isPrintState;
}
if (isPrintState)
Sb.Append((Char) Ch);
}
}
Console.Write(Sb.ToString());
Amidst so many good looking answer, mine might not be so sophisticated but I thought I would post it anyways. Simple logic.
var take = 3;
var skip = 2;
StringBuilder source = new StringBuilder("ABCDEFGHIJKL");
StringBuilder result = new StringBuilder();
while (source.Length > 0)
{
if (source.Length >= take)
{
result.Append(source.ToString().Substring(0, take));
}
else
{
result.Append(source.ToString());
}
if (source.Length > skip + take)
{
source.Remove(0, skip + take);
}
else
source.Clear();
}
This how to do that.
I think this may be more clear if you are not familiar with Lambda expression
int print = 3;
int skip = 2;
string str = "ABCDEFGHILKL";
StringBuilder stringBuilder = new StringBuilder();
string res = String.Empty;
int i = 0;
while (i < str.Length)
{
stringBuilder.Append(str.Substring(i, Math.Min(print, str.Length - i)));
i += print + skip;
}
Console.WriteLine(stringBuilder.ToString());

csharp method that choose every second character from the word

I need a method that returns every other character in a string starting with the first character. For example, a method call with ("Java-language") returns "Jv-agae."
private static void NewMethod(string word)
{
// here comes the code
}
var str = "Java-language";
var xx = new string(str.Where((ch, index) => index % 2 == 0).ToArray());
Console.WriteLine(xx);
Or this one:
var xx = string.Join<char>("", str.Where((ch, index) => (index & 1) == 0));
probably little different then everybody else: :-)
protected static IEnumerable<char> EverySecondChar(string word)
{
for(int i = 0; i < word.Length; i += 2)
yield return word[i];
}
string result = new string(EverySecondChar("Java-language").ToArray());
Here is my suggestion for you:
private string TakeEverySecondChar(string input)
{
var result = string.Empty;
for (int i = 0; i < input.Length; i+=2)
{
result += input.Substring(i, 1);
}
return result;
}
Console.Clear();
string Lang = "Java-language";
string[] LangArr = new string[Lang.Length];
char LangChar;
for (int i = 0; i < Lang.Length; i++)
{
LangChar = Lang[i];
LangArr[i] = LangChar.ToString();
}
for (int i = 0; i < LangArr.Length; i++)
{
Console.Write(LangArr[i]);
i++;
}
Console.ReadLine();
public String strip2ndchar(string text)
{
string final="";
int i = 0;
foreach (char a in text.ToCharArray())
{
if (i % 2 == 0)
final += a;
i++;
}
return final;
}

.NET C# Logic Function, recurrent function

I have some string in format like that
XXXX-XXXX-X_X_
All "_" should be replaced with Letters and numberst to prodce sth like that:
XXXX-XXXX-XAXA
XXXX-XXXX-XAXB
XXXX-XXXX-XAXC
XXXX-XXXX-XAXD
XXXX-XXXX-XAXE
XXXX-XXXX-XAXF
XXXX-XXXX-XAXG
(...)
XXXX-XXXX-XZX8
XXXX-XXXX-XZX9
XXXX-XXXX-X0XA
(...)
XXXX-XXXX-X2XA
XXXX-XXXX-X2XB
I know hoe to make it with one "_".
string alphaLetters = "ABCDEFGHIJKLMNOPQRSTUWXYZ0123456789ABCDEF";
foreach (char letter in alphaLetters.ToCharArray())
{
Numbers.Add(number.Replace('_', letter)));
}
I want this code to be working with unknown number of "_".
Can you help?
IMHO it must be recursive. (Note: that does not mean it must use recursive method call, although I used recursive call in the following code, it can be easily converted to internal recursion stack. )
public static void RunSnippet()
{
var r = new List<string>();
Replace("asd_asd_asd_".ToCharArray(), 0, r);
foreach(var s in r) { Console.WriteLine(s); }
}
public static char[] possibilities = new char[] { 'A', 'B', 'C' };
public static void Replace(char[] chars, int startIndex, IList<string> result)
{
for (int i = startIndex; i < chars.Length; i++)
{
if (chars[i] != '_')
{
continue;
}
// we found first '_'
for (int j = 0; j < possibilities.Length; j++)
{
chars[i] = possibilities[j];
Replace(chars, i + 1, result);
}
chars[i] = '_'; // take back what we replaced
return; //we're done here
}
// we didn't find any '_', so all were replaced and we have result:
result.Add(new string(chars));
}
Try this one:
var alphaIndexes = new List<int>();
string alphaLetters = "ABCDEFGHIJKLMNOPQRSTUWXYZ0123456789ABCDEF";
for(int n = 0; n<Numbers.Count; n++) {
char[] numberLetters = Numbers[n].ToCharArray();
int position = 0;
for(int i = numberLetters.Length - 1; i>=0; i--) {
if(numberLetters[i] == '_') {
int alphaIndex = 0;
if(alphaIndexes.Count <= position)
alphaIndexes.Add(0);
else {
alphaIndex = alphaIndexes[position];
}
numberLetters[i] = alphaLetters[alphaIndex];
position++;
}
}
if(alphaIndexes.Count > 0) {
alphaIndexes[0]++;
for(int j = 0; j < alphaIndexes.Count; j++) {
if(alphaIndexes[j] >= alphaLetters.Length) {
alphaIndexes[j] = 0;
if (j < alphaIndexes.Count)
alphaIndexes[j+1]++;
}
}
}
Numbers[n] = new String(numberLetters);
Numbers[n].Dump();
}

Categories