Multiple iterations with multithreading - c#

I rewrote method, which initially was for only one thread, to work with many threads. Now, this method accepts two concurrent collections: ConcurrentBag, which was List, and ConcurrentQueue, which was Queue.
The purpose is to match two titles from both collection and make some logic, which is simple value assignment in ConcurrentBag items. I know, for sure, that all symbols in ConcurrentBag are in ConcurrentQueue.
When I wrote this for multi threads, it occured that some of titles do not match (~20%), which did not happen when there was on thread. Only during debugging I can match these titles and then values are assigned. There has to be some problem with iterating these two collections. Maybe in the same time many threads reads values from the same item, but only reading should not be problem?
Below code:
public void UpdateWithPercent(ref ConcurrentBag<Book> refList, ConcurrentQueue<Book> list)
{
var size = list.Count;
int numProcs = Environment.ProcessorCount;
var divider = CalculatBiggestDivider(size);
var nextIteration = 0;
var remainingWork = numProcs;
var internalRefList = refList;
using (ManualResetEvent mre = new ManualResetEvent(false))
{
for (int i = 0; i < numProcs; i++)
{
ThreadPool.QueueUserWorkItem(delegate
{
IEnumerable<Book> partialList;
while (-(nextIteration - Interlocked.Add(ref nextIteration, (partialList = DequeueChunk(list, divider)).Count()))> 0)
{
foreach (var item in partialList)
{
foreach (var x in internalRefList)
{
if (x.Title == item.Title)
{
x.Orders += item.Orders;
break;
}
};
}
}
if (Interlocked.Decrement(ref remainingWork) == 0)
{
mre.Set();
}
});
}
mre.WaitOne();
}
refList = internalRefList;
}
private int CalculatBiggestDivider(int count)
{
var divider = 1;
for (int i = 30; i > 0; i--)
{
if (count % i == 0)
{
divider = i;
break;
}
}
return divider;
}
private IEnumerable<T> DequeueChunk<T>(ConcurrentQueue<T> queue, int chunkSize)
{
for (int i = 0; i < chunkSize && queue.Count > 0; i++)
{
T item;
bool success = queue.TryDequeue(out item);
if (!success)
{
i = chunkSize;
continue;
}
yield return item;
}
}

Eventually I decided to resign from nestedloops and used ConcurrentDictionary. Now it works.
public void UpdateWithPercent(ref ConcurrentDictionary<string, Book> refList, List<Book> list, int ticker, int maxTimes)
{
var size = list.Count;
int numProcs = Environment.ProcessorCount;
var divider = CalculatBiggestDivider(size);
var nextIteration = 0;
var remainingWork = numProcs;
var internalRefList = refList;
using (ManualResetEvent mre = new ManualResetEvent(false))
{
for (int i = 0; i < numProcs; i++)
{
ThreadPool.QueueUserWorkItem(delegate
{
int index = 0;
while ((index = Interlocked.Add(ref nextIteration, divider) - divider) < size)
{
foreach (var item in list.GetRange(index, divider))
{
Book x;
if (internalRefList.TryGetValue(item.Title, out x))
{
x.Orders += item.Orders;
}
};
}
if (Interlocked.Decrement(ref remainingWork) == 0)
{
mre.Set();
}
});
}
mre.WaitOne();
}
refList = internalRefList;
}

Related

Reduce execution time c# algorithm

I'm solving Kattis' bokforing problem and one of the test cases fails due to execution time being too long (> 2 sec). Can anyone give me any advice on how I can improve?
class Program
{
static void Main(string[] args)
{
/* Inputs
3 5
SET 1 7
PRINT 1
PRINT 2
RESTART 33
PRINT 1
*/
string first = Console.ReadLine();
int N = Convert.ToInt32(first.Split(" ")[0]);
int Q = Convert.ToInt32(first.Split(" ")[1]);
int[] Accounts = new int[N];
string[] Operations = new string[Q];
for (int i = 0; i < Operations.Length; i++)
{
Operations[i] = Console.ReadLine();
}
for (int i = 0; i < Operations.Length; i++)
{
string[] op = Operations[i].Split(" ");
string operation = op[0];
int accountId = 0;
int ammont = 0;
if (operation == "SET")
{
accountId = Convert.ToInt32(op[1]);
ammont = Convert.ToInt16(op[2]);
Accounts[accountId - 1] = ammont;
}
if (operation == "PRINT")
{
accountId = Convert.ToInt32(op[1]);
Console.WriteLine(Accounts[accountId - 1]);
}
if (operation == "RESTART")
{
ammont = Convert.ToInt16(op[1]);
for (int j = 0; j <= N - 1; j++)
{
Accounts[j] = ammont;
}
}
}
}
}
First of all I copied recommended IO classes from FAQ to the solution, removed double loop (there is no need to loop twice - reading inputs first and then processing them) and then the main trick was to use Dictionary instead of array so there is no need to manually clear it/set amount to all items in it every time:
var scanner = new Scanner();
using(var writer = new BufferedStdoutWriter())
{
var N = scanner.NextInt();
var Q = scanner.NextInt();
var amount = 0;
var Accounts = new Dictionary<int, int>();
for (var i = 0; i < Q; i++)
{
var s = scanner.Next();
var accountId = 0;
if (s == "SET")
{
accountId = scanner.NextInt();
Accounts[accountId] = scanner.NextInt();
}
else if (s == "PRINT")
{
accountId = scanner.NextInt();
if (!Accounts.TryGetValue(accountId, out var value))
{
value = amount;
}
writer.WriteLine(value);
}
else if (s == "RESTART")
{
amount = scanner.NextInt();
Accounts = new Dictionary<int, int>();
}
}
}

How to search through a jagged array

This code should search an array of decimals for elements that are in a specified range, and return the number of occurrences of the elements that matches the range criteria.
The problem is that I am having trouble in accessing the jagged array, my code:
public static int GetDecimalsCount(decimal[] arrayToSearch, decimal[][] ranges)
{
if (arrayToSearch is null)
{
throw new ArgumentNullException(nameof(arrayToSearch));
}
else if (ranges is null)
{
throw new ArgumentNullException(nameof(ranges));
}
else
{
int sum = 0;
for (int i = 0; i < arrayToSearch.Length; i++)
{
for (int j = 0; j < ranges.Length; j++)
{
for (int n = 0; n < ranges[j].Length; n++)
{
if (arrayToSearch[i] >= ranges[j][n] && arrayToSearch[i] <= ranges[j][n + 1])
{
sum++;
}
}
}
}
return sum;
}
}
The ranges are from lowest to highest so it will always be arrays of two decimals
I was also confident this at least should work:
if (arrayToSearch[i] >= ranges[j][0] && arrayToSearch[i] <= ranges[j][1])
How does it not compare the array, I don't understand.
EDIT 1: Data in Arrays from Test
Inserting some of the test code, if you need full I can send it. It's a little long and it has unimportant test cases for other assignments.
private static readonly decimal[] ArrayWithFiveElements = { 0.1m, 0.2m, 0.3m, 0.4m, 0.5m };
private static readonly decimal[] ArrayWithFifteenElements = { decimal.MaxValue, -0.1m, -0.2m, decimal.One, -0.3m, -0.4m, -0.5m, decimal.Zero, 0.1m, 0.2m, 0.3m, 0.4m, 0.5m, decimal.MinusOne, decimal.MinValue };
[Test]
public void DecimalCounter_FiveElementsOneRange_ReturnsResult()
{
// Arrange
decimal[][] ranges =
{
new[] { 0.1m, 0.2m },
};
// Act
int actualResult = DecimalCounter.GetDecimalsCount(DecimalCounterTests.ArrayWithFiveElements, ranges);
// Assert
Assert.AreEqual(2, actualResult);
}
[Test]
public void DecimalCounter_FiveElementsTwoRanges_ReturnsResult()
{
// Arrange
decimal[][] ranges =
{
new[] { 0.1m, 0.2m },
new[] { 0.4m, 0.5m },
};
// Act
int actualResult = DecimalCounter.GetDecimalsCount(DecimalCounterTests.ArrayWithFiveElements, ranges);
// Assert
Assert.AreEqual(4, actualResult);
}
After fixing the errors pointed out in the comments I don't find any problem in the code ; https://dotnetfiddle.net/F6Yjy0
public static int GetDecimalsCount(decimal[] arrayToSearch, decimal[][] ranges)
{
if (arrayToSearch == null)
{
throw new ArgumentNullException(nameof(arrayToSearch));
}
else if (ranges == null)
{
throw new ArgumentNullException(nameof(ranges));
}
else
{
int sum = 0;
for (int i = 0; i < arrayToSearch.Length; i++)
{
for (int j = 0; j < ranges.Length; j++)
{
//for (int n = 0; n < ranges[j].Length; n++)
//{
if (arrayToSearch[i] >= ranges[j][0] && arrayToSearch[i] <= ranges[j][1])
{
sum++;
}
//}
}
}
return sum;
}
}
The innermost loop is rather pointless; it only runs once and can be replaced with indexing 0/1. Removing it also removes the OOB problem

Why is this yield break not breaking the loop?

I wrote a method that takes as input a sequence (it can also be an infinite sequence) and an integer count and returns a new sequence that contains count elements taken from the input sequence, that are in positions which are prime numbers.
For example, if I have a sequence {5,13,84,10,2,6} and count = 3, the result sequence is {84,10,6}.
The class I wrote:
public static class PrimeMethod
{
public static IEnumerable<T> TakePrime<T>(this IEnumerable<T> s, int count)
{
var result = new List<T>();
if (s == null)
throw new ArgumentNullException();
if (count <= 0)
throw new ArgumentOutOfRangeException();
int x = 0;
int y = 0;
foreach (var i in s)
{
if (checkIfPrime(x) && y < count)
{
result.Add(i);
y++;
}
x++;
}
return result;
}
public static bool checkIfPrime(int num)
{
if (num == 0 || num == 1)
return false;
bool flag = false;
for (int i = 2; i < num; i++)
if (num % i == 0)
{
flag = true;
break;
}
if (!flag)
return true;
return false;
}
}
Now I have to write a parameterized test that takes as input a sequence from 0 to infinite and a size integer. The test must make sure that the size of the resulting list is equal to the parameter size.
I wrote this:
[TestCase(7)]
[TestCase(182)]
public void Check_Size(int size)
{
var list = List_Integers(size);
var result = list.TakePrime(size);
Assert.That(()=>result.Count(),Is.EqualTo(size));
}
public IEnumerable<int> List_Integers(int size)
{
var i = 0;
var list = new List<int>();
while(true)
{
var j = i;
i++;
list.Add(j);
if (list.TakePrime(size).Count() > size)
yield break;
yield return j;
}
}
Although I used a yield break the test never stops. Why is this not working?
UPDATE:
I realized my mistake and I changed List_Integers to this:
public IEnumerable<int> List_Integers(int size)
{
var i = 0;
var list = new List<int>();
var incr = size+1;
while(true)
{
var j = i;
i++;
list.Add(j);
if (list.TakePrime(size).Count() >= incr)
yield break;
yield return j;
}
}
It's still not working and I don't understand why.
You call
list.TakePrime(size)
Which (as you described and implemented yourself) will return a maximum of size primes. Hence it will never be greater than size.
I found the solution which is this:
[TestCase(7)]
[TestCase(182)]
public void Check_Size(int size)
{
var incr = size + 1;
var list = List_Integers(incr);
var result = list.TakePrime(size);
Assert.That(()=>result.Count(),Is.EqualTo(size));
}
public IEnumerable<int> List_Integers(int size)
{
var i = 0;
var list = new List<int>();
while(true)
{
var j = i;
i++;
list.Add(j);
if (list.TakePrime(size).Count() >= size)
yield break;
yield return j;
}
}

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# list permutations with limited length

I have a list of Offers, from which I want to create "chains" (e.g. permutations) with limited chain lengths.
I've gotten as far as creating the permutations using the Kw.Combinatorics project.
However, the default behavior creates permutations in the length of the list count. I'm not sure how to limit the chain lengths to 'n'.
Here's my current code:
private static List<List<Offers>> GetPerms(List<Offers> list, int chainLength)
{
List<List<Offers>> response = new List<List<Offers>>();
foreach (var row in new Permutation(list.Count).GetRows())
{
List<Offers> innerList = new List<Offers>();
foreach (var mix in Permutation.Permute(row, list))
{
innerList.Add(mix);
}
response.Add(innerList);
innerList = new List<Offers>();
}
return response;
}
Implemented by:
List<List<AdServer.Offers>> lst = GetPerms(offers, 2);
I'm not locked in KWCombinatorics if someone has a better solution to offer.
Here's another implementation which I think should be faster than the accepted answer (and it's definitely less code).
public static IEnumerable<IEnumerable<T>> GetVariationsWithoutDuplicates<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items.Distinct()
from permutation in GetVariationsWithoutDuplicates(items.Where(i => !EqualityComparer<T>.Default.Equals(i, item)).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<IEnumerable<T>> GetVariations<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items
from permutation in GetVariations(Remove(item, items).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<T> Prepend<T>(T first, IEnumerable<T> rest)
{
yield return first;
foreach (var item in rest) yield return item;
}
public static IEnumerable<T> Remove<T>(T item, IEnumerable<T> from)
{
var isRemoved = false;
foreach (var i in from)
{
if (!EqualityComparer<T>.Default.Equals(item, i) || isRemoved) yield return i;
else isRemoved = true;
}
}
On my 3.1 GHz Core 2 Duo, I tested with this:
public static void Test(Func<IList<int>, int, IEnumerable<IEnumerable<int>>> getVariations)
{
var max = 11;
var timer = System.Diagnostics.Stopwatch.StartNew();
for (int i = 1; i < max; ++i)
for (int j = 1; j < i; ++j)
getVariations(MakeList(i), j).Count();
timer.Stop();
Console.WriteLine("{0,40}{1} ms", getVariations.Method.Name, timer.ElapsedMilliseconds);
}
// Make a list that repeats to guarantee we have duplicates
public static IList<int> MakeList(int size)
{
return Enumerable.Range(0, size/2).Concat(Enumerable.Range(0, size - size/2)).ToList();
}
Unoptimized
GetVariations 11894 ms
GetVariationsWithoutDuplicates 9 ms
OtherAnswerGetVariations 22485 ms
OtherAnswerGetVariationsWithDuplicates 243415 ms
With compiler optimizations
GetVariations 9667 ms
GetVariationsWithoutDuplicates 8 ms
OtherAnswerGetVariations 19739 ms
OtherAnswerGetVariationsWithDuplicates 228802 ms
You're not looking for a permutation, but for a variation. Here is a possible algorithm. I prefer iterator methods for functions that can potentially return very many elements. This way, the caller can decide if he really needs all elements:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
var variationElements = new HashSet<T>(); //for duplicate detection
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
var valid = true;
for (int i = 0; i < length; ++i)
{
var element = offers[startIndices[i]];
if (variationElements.Contains(element))
{
valid = false;
break;
}
variation.Add(element);
variationElements.Add(element);
}
if (valid)
yield return variation;
//Count up the indices
startIndices[length - 1]++;
for (int i = length - 1; i > 0; --i)
{
if (startIndices[i] >= offers.Count)
{
startIndices[i] = 0;
startIndices[i - 1]++;
}
else
break;
}
variationElements.Clear();
}
}
The idea for this algorithm is to use a number in offers.Count base. For three offers, all digits are in the range 0-2. We then basically increment this number step by step and return the offers that reside at the specified indices. If you want to allow duplicates, you can remove the check and the HashSet<T>.
Update
Here is an optimized variant that does the duplicate check on the index level. In my tests it is a lot faster than the previous variant:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
for (int i = 0; i < length; ++i)
startIndices[i] = i;
var indices = new HashSet<int>(); // for duplicate check
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
for (int i = 0; i < length; ++i)
{
variation.Add(offers[startIndices[i]]);
}
yield return variation;
//Count up the indices
AddOne(startIndices, length - 1, offers.Count - 1);
//duplicate check
var check = true;
while (check)
{
indices.Clear();
for (int i = 0; i <= length; ++i)
{
if (i == length)
{
check = false;
break;
}
if (indices.Contains(startIndices[i]))
{
var unchangedUpTo = AddOne(startIndices, i, offers.Count - 1);
indices.Clear();
for (int j = 0; j <= unchangedUpTo; ++j )
{
indices.Add(startIndices[j]);
}
int nextIndex = 0;
for(int j = unchangedUpTo + 1; j < length; ++j)
{
while (indices.Contains(nextIndex))
nextIndex++;
startIndices[j] = nextIndex++;
}
break;
}
indices.Add(startIndices[i]);
}
}
}
}
int AddOne(int[] indices, int position, int maxElement)
{
//returns the index of the last element that has not been changed
indices[position]++;
for (int i = position; i > 0; --i)
{
if (indices[i] > maxElement)
{
indices[i] = 0;
indices[i - 1]++;
}
else
return i;
}
return 0;
}
If I got you correct here is what you need
this will create permutations based on the specified chain limit
public static List<List<T>> GetPerms<T>(List<T> list, int chainLimit)
{
if (list.Count() == 1)
return new List<List<T>> { list };
return list
.Select((outer, outerIndex) =>
GetPerms(list.Where((inner, innerIndex) => innerIndex != outerIndex).ToList(), chainLimit)
.Select(perms => (new List<T> { outer }).Union(perms).Take(chainLimit)))
.SelectMany<IEnumerable<IEnumerable<T>>, List<T>>(sub => sub.Select<IEnumerable<T>, List<T>>(s => s.ToList()))
.Distinct(new PermComparer<T>()).ToList();
}
class PermComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<T> obj)
{
return (int)obj.Average(o => o.GetHashCode());
}
}
and you'll call it like this
List<List<AdServer.Offers>> lst = GetPerms<AdServer.Offers>(offers, 2);
I made this function is pretty generic so you may use it for other purpose too
eg
List<string> list = new List<string>(new[] { "apple", "banana", "orange", "cherry" });
List<List<string>> perms = GetPerms<string>(list, 2);
result

Categories