Recursion - what am I doing wrong? - c#

I need to sort out the values in such a way that the toReturn list should contain the following:
Test(1100, 1130)
Test(1134, 1200)
Test(1210, 1310)
Test(1100, 1140)
Test(1145, 1210)
Test(1220, 1320)
I get:
Test(1100, 1130)
Test(1134, 1200)
Test(1210, 1310)
Test(1100, 1140)
Test(1145, 1210)
Test(1134, 1200)
Test(1220, 1320)
Basically, looping through the three lists and checking if the Start of second is > End of first.
I have tried various ways to solve this and this the closest I could get, but still don't get the results as I expect.
Can someone please advise what I might be doing wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication22
{
class Program
{
static List<Test> toReturn = new List<Test>();
static void Main(string[] args)
{
List<Test> l1 = new List<Test>();
l1.Add(new Test(1100, 1130));
l1.Add(new Test(1100, 1140));
l1.Add(new Test(1110, 1150));
List<Test> l2 = new List<Test>();
l2.Add(new Test(1134, 1200));
l2.Add(new Test(1145, 1210));
List<Test> l3 = new List<Test>();
l3.Add(new Test(1210, 1310));
l3.Add(new Test(1220, 1320));
List<List<Test>> container = new List<List<Test>>();
container.Add(l1);
container.Add(l2);
container.Add(l3);
sort(container, 0, 0);
}
private static void sort(List<List<Test>> temp, int position, int time)
{
if (position + 1 == temp.Count)
{
return;
}
List<Test> tt = temp[position];
if (position + 1 < temp.Count)
{
List<Test> tt1 = temp[position + 1];
for (int i = 0; i < tt.Count; i++)
{
int t1 = tt[i].End;
for (int j = 0; j < tt1.Count; j++)
{
int t2 = tt1[j].Start;
if (t2 > t1 && t2 > time)
{
//if (toReturn.Count == 0)
//{
if (toReturn.Count == 0)
{
toReturn.Add(tt[i]);
}
else
{
if (toReturn[toReturn.Count - 1].End != tt[i].End && toReturn[toReturn.Count - 1].Start != tt[i].Start)
{
toReturn.Add(tt[i]);
}
}
if (toReturn[toReturn.Count - 1].End != tt1[j].End && toReturn[toReturn.Count - 1].Start != tt1[j].Start)
{
toReturn.Add(tt1[j]);
}
sort(temp, position + 1, tt1[j].End);
break;
}
}
if (position > 0)
{
return;
}
}
}
String val = "";
//return toReturn;
}
}
class Test
{
int start;
public Test(int val1, int val2)
{
Start = val1;
End = val2;
}
public int Start
{
get { return start; }
set { start = value; }
}
int end;
public int End
{
get { return end; }
set { end = value; }
}
}
}

Use a comparator, as suggested: An element is less than another if its End is less than the other's Start. An element is greater than another if its Start is greater than the other's End.
class TestComparer : IComparer<Test>
{
int Compare(Test a, Test b)
{
if (a.End < b.Start) return -1;
else if (a.Start > b.End) return 1;
else return 0;
}
}
...
List.Sort(list, new TestComparer());
Edit After re-reading your question, I would follow an approach like the one below:
While there is an element left in the list
Find element with smallest Start
Add it to the resulting list, and remove it from the list
While an element with a larger Start then the last item's End in the resulting list exists
Add it to the resulting list, and remove it from the list
Something like:
while (list.Count > 0)
{
int i = GetSmallestTestIdx(list);
do
{
result.Add(list[i]);
list.RemoveAt(i);
}
while ((i = GetNextTextIdx(list, result)) != -1);
}

Related

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;
}
}

Cleaner Algorithm for List of Possibly Intersecting Ranges With Properties

I have these objects with a range and list of properties. My goal is to take a list of these objects and create a new list where no ranges overlap. When two ranges are overlapping the overlapping region can be replaced with an object with the union of the properties. I'm hoping a picture can explain this a little better than words can.
Untangling Of Ranges
I was able to achieve this with the following code however it is rather clunky and uses a goto which I try to avoid. The methodology behind this code is to compare every pair of ranges and if there is an intersection, replace both RangeObjects with up to three RangeObjects:
One for the part of rangeObject1 that doesn't intersect rangeObject2
One for the part of rangeObject2 that doesn't intersect rangeObject1
One for the intersection of rangeObject1 and rangeObject2 with unioned properties.
class RangeObject
{
RangeObject(int start, int end, List<object> properties)
{
Start = start;
End = end;
Properties = properties;
}
public int Start { get; set; }
public int End { get; set; }
public int Length { get => End - Start; }
public List<object> Properties { get; }
public bool IsInRange(int value)
{
return value > Start && value < End;
}
private List<RangeObject> UntangleRangeList(List<RangeObject> list)
{
List<RangeObject> list1 = new List<RangeObject>(list);
list1.Sort();
int start = 0;
startover:
for (int i = start; i < list1.Count; i++)
{
for (int j = i + 1; j < list1.Count; j++)
{
if (list1[i].Start < list1[j].End && list1[j].Start < list1[i].End)
{
list1.AddRange(UntangleRanges(list1[i], list1[j]));
list1.Remove(list1[j]);
list1.Remove(list1[i]);
goto startover;
}
}
start++;
}
list1.Sort();
return list1;
}
public List<RangeObject> UntangleRanges(RangeObject rangeObject1, RangeObject rangeObject2)
{
List<RangeObject> result = new List<RangeObject>();
//This is to reduce the number of if cases by allowing the asumption that rangeObject1 is first
if (rangeObject1.Start > rangeObject2.Start || ((rangeObject1.Start == rangeObject2.Start) && (rangeObject1.Length > rangeObject2.Length)))
{
RangeObject temp = rangeObject1;
rangeObject1 = rangeObject2;
rangeObject2 = temp;
}
if (rangeObject1.Start == rangeObject2.Start && rangeObject1.End == rangeObject2.End) //Ranges Equal
{
result.Add(new RangeObject(rangeObject1.Start, rangeObject1.End, rangeObject1.Properties.Union(rangeObject2.Properties).ToList()));//Return a RangeObject of Unioned Properties
}
else if(rangeObject1.IsInRange(rangeObject2.Start) && rangeObject1.IsInRange(rangeObject2.End))//Range2 contained in Range1
{
if (rangeObject1.Start != rangeObject2.Start)
{
result.Add(new RangeObject(rangeObject1.Start, rangeObject2.Start - rangeObject1.Start, rangeObject1.Properties));
}
result.Add(new RangeObject(rangeObject2.Start, rangeObject2.Length, rangeObject1.Properties.Union(rangeObject2.Properties).ToList()));
if (rangeObject1.End != rangeObject2.End)
{
result.Add(new RangeObject(rangeObject2.End, rangeObject1.End - rangeObject2.End, rangeObject1.Properties));
}
}
else if (rangeObject1.IsInRange(rangeObject2.Start))//Range2.Start contained in Range1
{
result.Add(new RangeObject(rangeObject1.Start, rangeObject2.Start - rangeObject1.Start, rangeObject1.Properties));
result.Add(new RangeObject(rangeObject2.Start, rangeObject1.End - rangeObject2.Start, rangeObject1.Properties.Union(rangeObject2.Properties).ToList()));
result.Add(new RangeObject(rangeObject1.End, rangeObject2.End - rangeObject1.End, rangeObject2.Properties));
}
else //No intersection, shouldn't happen
{
result.Add(rangeObject1);
result.Add(rangeObject2);
}
return result;
}
}
Any ideas on how to achieve this a little more elegantly? Or at least avoid the startover because when I cut up the ranges I end up relocating them to the end and changing the length/order of the list so it's hard to tell what ranges I've compared.
For the sake of simplicity I first get a big enough range to include all other ranges, but with an empty Properties field. This is achieved by getting the minimum and maximum value of all ranges.
Then I combine the ranges one after the other with a so-called untangled range list which at the beginning consists of only initialRange. During this process, untangledRanges remains sorted and without any overlapping ranges. So in the end, all the ranges are combined into a list of untangled ranges.
Based on your current code, this is all you need:
class RangeObject
{
public RangeObject(int start, int end, List<object> properties)
{
if (start >= end)
throw new Exception("'start' must be less than 'end'");
Start = start;
End = end;
Properties = properties;
}
public int Start { get; set; }
public int End { get; set; }
public int Length { get => End - Start; }
public List<object> Properties { get; set; }
public List<RangeObject> SplitAt(int point)
{
if (point <= this.Start || point >= this.End)
return new List<RangeObject> { this };
var result = new List<RangeObject>();
result.Add(new RangeObject(this.Start, point, this.Properties));
result.Add(new RangeObject(point, this.End, this.Properties));
return result;
}
public static List<RangeObject> UntangleRangeList(List<RangeObject> list)
{
var initialRange = GetInitialRange(list);
var untangledRanges = new List<RangeObject> { initialRange };
foreach (var rangeObject in list)
{
ExpandUntangleRanges(untangledRanges, rangeObject);
}
return untangledRanges;
}
private static void ExpandUntangleRanges(
List<RangeObject> alreadyUntangledRanges, RangeObject newRange)
{
int firstRangeIndex = alreadyUntangledRanges
.FindIndex(x => x.Start <= newRange.Start && newRange.Start < x.End);
int lastRangeIndex = alreadyUntangledRanges
.FindIndex(x => x.Start < newRange.End && newRange.End <= x.End);
var firstRange = alreadyUntangledRanges[firstRangeIndex];
if (firstRange.Start < newRange.Start)
{
// split the first range
alreadyUntangledRanges.RemoveAt(firstRangeIndex);
alreadyUntangledRanges.InsertRange(
firstRangeIndex, firstRange.SplitAt(newRange.Start));
firstRangeIndex++;
lastRangeIndex++;
}
var lastRange = alreadyUntangledRanges[lastRangeIndex];
if (newRange.End < lastRange.End)
{
// split the last range
alreadyUntangledRanges.RemoveAt(lastRangeIndex);
alreadyUntangledRanges.InsertRange(
lastRangeIndex, lastRange.SplitAt(newRange.End));
}
for (int i = firstRangeIndex; i <= lastRangeIndex; i++)
{
alreadyUntangledRanges[i].Properties = alreadyUntangledRanges[i]
.Properties.Union(newRange.Properties).ToList();
}
}
private static RangeObject GetInitialRange(List<RangeObject> rangeObjects)
{
int? start = null;
int? end = null;
foreach (var rangeObject in rangeObjects)
{
if (start == null || rangeObject.Start < start)
start = rangeObject.Start;
if (end == null || rangeObject.End > end)
end = rangeObject.End;
}
if (start == null || end == null)
return null;
return new RangeObject(start.Value, end.Value, new List<object>());
}
}
The following is one way to get rid of goto:
private List<RangeObject> UntangleRangeList(List<RangeObject> list)
{
List<RangeObject> list1 = new List<RangeObject>(list);
list1.Sort();
int start = 0;
while (!CheckSomething(list1, ref start)) ;
list1.Sort();
return list1;
}
private bool CheckSomething(List<RangeObject> list1, ref int start)
{
for (int i = start; i < list1.Count; i++)
{
for (int j = i + 1; j < list1.Count; j++)
{
if (list1[i].Start < list1[j].End && list1[j].Start < list1[i].End)
{
list1.AddRange(UntangleRanges(list1[i], list1[j]));
list1.Remove(list1[j]);
list1.Remove(list1[i]);
return false;
}
}
start++;
}
return true;
}

c# Multi Threading only using 25% of CPU

I have a process for a sort of genetic nesting algorithm that I am trying to multi-thread. The process looks something like the following.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
CurrentNest = new CuttingRun();
for (int i = 0; i < 80; i++)
{
double w = GetRandomNumber(24, 50);
double h = GetRandomNumber(10, 15);
CurrentNest.PartList.Add(new LwCube { Width = w, Height = h, PartID = i });
}
//Task.Run(() =>
//{
// Parallel.For(0, 64, (i) => Parallel_Nest());
//});
while (true)
{
Parallel_Nest();
}
//Console.ReadKey();
}
public static double GetRandomNumber(double minimum, double maximum)
{
Random random = new Random();
return random.NextDouble() * (maximum - minimum) + minimum;
}
public static CuttingRun CurrentNest { get; set; }
public static void Parallel_Nest()
{
Random random = new Random();
int randomNumber = random.Next(2000, 10000);
var retVal = Nester.Nest_Parts(CurrentNest, randomNumber);
CurrentNest.Iterations++;
if (CurrentNest.SavedList.Count > 0)
{
if (retVal.Count < CurrentNest.SavedList.Count)
{
CurrentNest.SavedList = retVal;
}
}
else
{
CurrentNest.SavedList = retVal;
}
Console.WriteLine(CurrentNest.Iterations.ToString() + " " + CurrentNest.SavedList.Count.ToString());
if (CurrentNest.SavedList != retVal)
{
retVal.Clear();
}
}
}
//Models
public class LwSheet
{
public LwSheet(double width, double height)
{
SheetWidth = width;
SheetHeight = height;
FreeRectangles.Add(new LwCube { Width = width, Height = height, X = 0, Y = 0 });
}
public List<LwCube> UsedRectangles = new List<LwCube>();
public List<LwCube> FreeRectangles = new List<LwCube>();
public double SheetWidth { get; set; }
public double SheetHeight { get; set; }
public double TotalUsed { get; set; }
public bool Place_Part(LwCube prt)
{
bool retVal = false;
LwCube bestNode = FindPositionForBestAreaFit(prt);
//if the bestNode has a height then add our parts to the list
if (bestNode.Height > 0)
{
bestNode.PartID = prt.PartID;
int numRectanglesToProcess = FreeRectangles.Count;
for (int i = 0; i < numRectanglesToProcess; ++i)
{
if (SplitFreeNode(FreeRectangles[i], ref bestNode))
{
FreeRectangles.RemoveAt(i);
--i;
--numRectanglesToProcess;
}
}
PruneFreeList();
UsedRectangles.Add(bestNode);
retVal = true;
}
return retVal;
}
bool SplitFreeNode(LwCube freeNode, ref LwCube usedNode)
{
// Test with SAT if the rectangles even intersect.
if (usedNode.X >= freeNode.X + freeNode.Width || usedNode.X + usedNode.Width <= freeNode.X ||
usedNode.Y >= freeNode.Y + freeNode.Height || usedNode.Y + usedNode.Height <= freeNode.Y)
return false;
if (usedNode.X < freeNode.X + freeNode.Width && usedNode.X + usedNode.Width > freeNode.X)
{
// New node at the top side of the used node.
if (usedNode.Y > freeNode.Y && usedNode.Y < freeNode.Y + freeNode.Height)
{
LwCube newNode = new LwCube { Width = freeNode.Width, X = freeNode.X, Y = freeNode.Y };
newNode.Height = usedNode.Y - newNode.Y;
FreeRectangles.Add(newNode);
}
// New node at the bottom side of the used node.
if (usedNode.Y + usedNode.Height < freeNode.Y + freeNode.Height)
{
LwCube newNode = new LwCube { Width = freeNode.Width, X = freeNode.X };
newNode.Y = usedNode.Y + usedNode.Height;
newNode.Height = freeNode.Y + freeNode.Height - (usedNode.Y + usedNode.Height);
FreeRectangles.Add(newNode);
}
}
if (usedNode.Y < freeNode.Y + freeNode.Height && usedNode.Y + usedNode.Height > freeNode.Y)
{
// New node at the left side of the used node.
if (usedNode.X > freeNode.X && usedNode.X < freeNode.X + freeNode.Width)
{
LwCube newNode = new LwCube { Height = freeNode.Height, X = freeNode.X, Y = freeNode.Y };
newNode.Width = usedNode.X - newNode.X;
FreeRectangles.Add(newNode);
}
// New node at the right side of the used node.
if (usedNode.X + usedNode.Width < freeNode.X + freeNode.Width)
{
LwCube newNode = new LwCube { Height = freeNode.Height, Y = freeNode.Y };
newNode.X = usedNode.X + usedNode.Width;
newNode.Width = freeNode.X + freeNode.Width - (usedNode.X + usedNode.Width);
FreeRectangles.Add(newNode);
}
}
return true;
}
void PruneFreeList()
{
for (int i = 0; i < FreeRectangles.Count; ++i)
for (int j = i + 1; j < FreeRectangles.Count; ++j)
{
if (IsContainedIn(FreeRectangles[i], FreeRectangles[j]))
{
FreeRectangles.RemoveAt(i);
--i;
break;
}
if (IsContainedIn(FreeRectangles[j], FreeRectangles[i]))
{
FreeRectangles.RemoveAt(j);
--j;
}
}
}
bool IsContainedIn(LwCube a, LwCube b)
{
return a.X >= b.X && a.Y >= b.Y
&& a.X + a.Width <= b.X + b.Width
&& a.Y + a.Height <= b.Y + b.Height;
}
LwCube FindPositionForBestAreaFit(LwCube prt)
{
LwCube bestNode = new LwCube();
var bestAreaFit = SheetWidth * SheetHeight;
for (int i = 0; i < FreeRectangles.Count; ++i)
{
double areaFit = FreeRectangles[i].Width * FreeRectangles[i].Height - prt.Width * prt.Height;
// Try to place the rectangle in upright (non-flipped) orientation.
if (FreeRectangles[i].Width >= prt.Width && FreeRectangles[i].Height >= prt.Height)
{
if (areaFit < bestAreaFit)
{
bestNode.X = FreeRectangles[i].X;
bestNode.Y = FreeRectangles[i].Y;
bestNode.Height = prt.Height;
bestNode.Width = prt.Width;
bestAreaFit = areaFit;
}
}
}
return bestNode;
}
}
public class LwCube
{
public int PartID { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double X { get; set; }
public double Y { get; set; }
}
public class CuttingRun
{
public List<LwCube> PartList = new List<LwCube>();
public List<LwSheet> SavedList = new List<LwSheet>();
public List<LwSheet> Sheets = new List<LwSheet>();
public int Iterations { get; set; }
}
//Actions
public static class Nester
{
public static List<LwSheet> Nest_Parts(CuttingRun cuttingRun, int loopCount)
{
var SheetList = new List<LwSheet>();
List<LwCube> partList = new List<LwCube>();
partList.AddRange(cuttingRun.PartList);
while (partList.Count > 0)
{
LwSheet newScore = new LwSheet(97, 49);
List<LwCube> addingParts = new List<LwCube>();
foreach (var prt in partList)
{
addingParts.Add(new LwCube { Width = prt.Width, Height = prt.Height, PartID = prt.PartID });
}
if (addingParts.Count > 0)
{
var sheets = new ConcurrentBag<LwSheet>();
Parallel.For(0, loopCount, (i) =>
{
var hmr = new LwSheet(97, 49);
Add_Parts_To_Sheet(hmr, addingParts);
sheets.Add(hmr);
});
//for (int i = 0; i < loopCount; i++)
//{
// var hmr = new LwSheet(97, 49);
// Add_Parts_To_Sheet(hmr, addingParts, addToLarge, addToMedium);
// sheets.Add(hmr);
//}
addingParts.Clear();
var bestSheet = sheets.Where(p => p != null).OrderByDescending(p => p.TotalUsed).First();
sheets = null;
newScore = bestSheet;
foreach (var ur in newScore.UsedRectangles)
{
partList.Remove(partList.Single(p => p.PartID == ur.PartID));
}
SheetList.Add(newScore);
}
}
return SheetList;
}
public static void Add_Parts_To_Sheet(LwSheet sh, List<LwCube> parts)
{
var myList = new List<LwCube>();
myList.AddRange(parts);
myList.Shuffle();
foreach (var prt in myList)
{
sh.Place_Part(prt);
}
myList.Clear();
foreach (var ur in sh.UsedRectangles)
{
sh.TotalUsed += ur.Width * ur.Height;
}
}
[ThreadStatic] private static Random Local;
public static Random ThisThreadsRandom
{
get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + System.Threading.Thread.CurrentThread.ManagedThreadId))); }
}
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = ThisThreadsRandom.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
}
I have tried using parallel for loops on each of the loops to try and speed up the process. I have also tried changing them to tasks and used task.WhenAll. However I am only able to use around 25% of my CPU. If I start the program 4 different times, I can use 100%.
I am wondering if anyone has any ideas on how I could use 100% of my CPU without starting the program more than once?
EDIT: After adding a scaled down working version I also commented out one of the parallel loops and one of the normal loops to show where I put them in the code.
However I am only able to use around 25% of my CPU. If I start the program 4 different times, I can use 100%. I am wondering if anyone has any ideas on how I could use 100% of my CPU without starting the program more than once?
Your code appears to be a mixture of asynchronous (presumably I/O-bound) and parallel (presumably CPU-bound) portions. I say "appears to be" because we can't say for sure where the problem is since this is not a minimal reproducible example.
But, if that assumption is correct, then the reason your CPU is underutilized is simple: the parallel CPU-bound portions are waiting for their input data from the asynchronous I/O-bound portions. The only way to fix that is to run the I/O-bound portions concurrently. Move your I/O-bound code as early in the pipeline as possible, and then be sure to run the I/O-bound portions as concurrently as possible. E.g., if you have to call a WebApi for each item, call it as soon as you have the item; or if you're reading items from a database, try to read as many in a batch as possible. This is to minimize the amount of time that the CPU-bound portions have to wait for their data.
"Asynchronous Parallel ForEach" is rarely a good tool for this kind of problem. I would either look into TPL Dataflow or build your own pipeline using Channels.
At the end of the day, it is possible that the algorithm as a whole is I/O-bound. In that case, there isn't a whole lot you can do: only one CPU would be used because the I/O couldn't even keep up with that single CPU, and in that case using more CPUs wouldn't provide any benefit.

Find the missing integer in Codility

I need to "Find the minimal positive integer not occurring in a given sequence. "
A[0] = 1
A[1] = 3
A[2] = 6
A[3] = 4
A[4] = 1
A[5] = 2, the function should return 5.
Assume that:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [−2,147,483,648..2,147,483,647].
I wrote the code in codility, but for many cases it did not worked and the performance test gives 0 %. Please help me out, where I am wrong.
class Solution {
public int solution(int[] A) {
if(A.Length ==0) return -1;
int value = A[0];
int min = A.Min();
int max = A.Max();
for (int j = min+1; j < max; j++)
{
if (!A.Contains(j))
{
value = j;
if(value > 0)
{
break;
}
}
}
if(value > 0)
{
return value;
}
else return 1;
}
}
The codility gives error with all except the example, positive and negative only values.
Edit: Added detail to answer your actual question more directly.
"Please help me out, where I am wrong."
In terms of correctness: Consider A = {7,2,5,6,3}. The correct output, given the contents of A, is 1, but our algorithm would fail to detect this since A.Min() would return 2 and we would start looping from 3 onward. In this case, we would return 4 instead; since it's the next missing value.
Same goes for something like A = {14,15,13}. The minimal missing positive integer here is again 1 and, since all the values from 13-15 are present, the value variable will retain its initial value of value=A[0] which would be 14.
In terms of performance: Consider what A.Min(), A.Max() and A.Contains() are doing behind the scenes; each one of these is looping through A in its entirety and in the case of Contains, we are calling it repeatedly for every value between the Min() and the lowest positive integer we can find. This will take us far beyond the specified O(N) performance that Codility is looking for.
By contrast, here's the simplest version I can think of that should score 100% on Codility. Notice that we only loop through A once and that we take advantage of a Dictionary which lets us use ContainsKey; a much faster method that does not require looping through the whole collection to find a value.
using System;
using System.Collections.Generic;
class Solution {
public int solution(int[] A) {
// the minimum possible answer is 1
int result = 1;
// let's keep track of what we find
Dictionary<int,bool> found = new Dictionary<int,bool>();
// loop through the given array
for(int i=0;i<A.Length;i++) {
// if we have a positive integer that we haven't found before
if(A[i] > 0 && !found.ContainsKey(A[i])) {
// record the fact that we found it
found.Add(A[i], true);
}
}
// crawl through what we found starting at 1
while(found.ContainsKey(result)) {
// look for the next number
result++;
}
// return the smallest positive number that we couldn't find.
return result;
}
}
The simplest solution that scored perfect score was:
public int solution(int[] A)
{
int flag = 1;
A = A.OrderBy(x => x).ToArray();
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= 0)
continue;
else if (A[i] == flag)
{
flag++;
}
}
return flag;
}
Fastest C# solution so far for [-1,000,000...1,000,000].
public int solution(int[] array)
{
HashSet<int> found = new HashSet<int>();
for (int i = 0; i < array.Length; i++)
{
if (array[i] > 0)
{
found.Add(array[i]);
}
}
int result = 1;
while (found.Contains(result))
{
result++;
}
return result;
}
A tiny version of another 100% with C#
using System.Linq;
class Solution
{
public int solution(int[] A)
{
// write your code in C# 6.0 with .NET 4.5 (Mono)
var i = 0;
return A.Where(a => a > 0).Distinct().OrderBy(a => a).Any(a => a != (i = i + 1)) ? i : i + 1;
}
}
A simple solution that scored 100% with C#
int Solution(int[] A)
{
var A2 = Enumerable.Range(1, A.Length + 1);
return A2.Except(A).First();
}
public class Solution {
public int solution( int[] A ) {
return Arrays.stream( A )
.filter( n -> n > 0 )
.sorted()
.reduce( 0, ( a, b ) -> ( ( b - a ) > 1 ) ? a : b ) + 1;
}
}
It seemed easiest to just filter out the negative numbers. Then sort the stream. And then reduce it to come to an answer. It's a bit of a functional approach, but it got a 100/100 test score.
Got an 100% score with this solution:
https://app.codility.com/demo/results/trainingUFKJSB-T8P/
public int MissingInteger(int[] A)
{
A = A.Where(a => a > 0).Distinct().OrderBy(c => c).ToArray();
if (A.Length== 0)
{
return 1;
}
for (int i = 0; i < A.Length; i++)
{
//Console.WriteLine(i + "=>" + A[i]);
if (i + 1 != A[i])
{
return i + 1;
}
}
return A.Max() + 1;
}
JavaScript solution using Hash Table with O(n) time complexity.
function solution(A) {
let hashTable = {}
for (let item of A) {
hashTable[item] = true
}
let answer = 1
while(true) {
if(!hashTable[answer]) {
return answer
}
answer++
}
}
The Simplest solution for C# would be:
int value = 1;
int min = A.Min();
int max = A.Max();
if (A.Length == 0) return value = 1;
if (min < 0 && max < 0) return value = 1;
List<int> range = Enumerable.Range(1, max).ToList();
List<int> current = A.ToList();
List<int> valid = range.Except(current).ToList();
if (valid.Count() == 0)
{
max++;
return value = max;
}
else
{
return value = valid.Min();
}
Considering that the array should start from 1 or if it needs to start from the minimum value than the Enumerable.range should start from Min
MissingInteger solution in C
int solution(int A[], int N) {
int i=0,r[N];
memset(r,0,(sizeof(r)));
for(i=0;i<N;i++)
{
if(( A[i] > 0) && (A[i] <= N)) r[A[i]-1]=A[i];
}
for(i=0;i<N;i++)
{
if( r[i] != (i+1)) return (i+1);
}
return (N+1);
}
My solution for it:
public static int solution()
{
var A = new[] { -1000000, 1000000 }; // You can try with different integers
A = A.OrderBy(i => i).ToArray(); // We sort the array first
if (A.Length == 1) // if there is only one item in the array
{
if (A[0]<0 || A[0] > 1)
return 1;
if (A[0] == 1)
return 2;
}
else // if there are more than one item in the array
{
for (var i = 0; i < A.Length - 1; i++)
{
if (A[i] >= 1000000) continue; // if it's bigger than 1M
if (A[i] < 0 || (A[i] + 1) >= (A[i + 1])) continue; //if it's smaller than 0, if the next integer is bigger or equal to next integer in the sequence continue searching.
if (1 < A[0]) return 1;
return A[i] + 1;
}
}
if (1 < A[0] || A[A.Length - 1] + 1 == 0 || A[A.Length - 1] + 1 > 1000000)
return 1;
return A[A.Length-1] +1;
}
class Solution {
public int solution(int[] A) {
int size=A.length;
int small,big,temp;
for (int i=0;i<size;i++){
for(int j=0;j<size;j++){
if(A[i]<A[j]){
temp=A[j];
A[j]=A[i];
A[i]=temp;
}
}
}
int z=1;
for(int i=0;i<size;i++){
if(z==A[i]){
z++;
}
//System.out.println(a[i]);
}
return z;
}
enter code here
}
In C# you can solve the problem by making use of built in library functions. How ever the performance is low for very large integers
public int solution(int[] A)
{
var numbers = Enumerable.Range(1, Math.Abs(A.Max())+1).ToArray();
return numbers.Except(A).ToArray()[0];
}
Let me know if you find a better solution performance wise
C# - MissingInteger
Find the smallest missing integer between 1 - 1000.000.
Assumptions of the OP take place
TaskScore/Correctness/Performance: 100%
using System;
using System.Linq;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
var A = new int[] { -122, -5, 1, 2, 3, 4, 5, 6, 7 }; // 8
var B = new int[] { 1, 3, 6, 4, 1, 2 }; // 5
var C = new int[] { -1, -3 }; // 1
var D = new int[] { -3 }; // 1
var E = new int[] { 1 }; // 2
var F = new int[] { 1000000 }; // 1
var x = new int[][] { A, B, C, D, E, F };
x.ToList().ForEach((arr) =>
{
var s = new Solution();
Console.WriteLine(s.solution(arr));
});
Console.ReadLine();
}
}
// ANSWER/SOLUTION
class Solution
{
public int solution(int[] A)
{
// clean up array for negatives and duplicates, do sort
A = A.Where(entry => entry > 0).Distinct().OrderBy(it => it).ToArray();
int lowest = 1, aLength = A.Length, highestIndex = aLength - 1;
for (int i = 0; i < aLength; i++)
{
var currInt = A[i];
if (currInt > lowest) return lowest;
if (i == highestIndex) return ++lowest;
lowest++;
}
return 1;
}
}
}
Got 100% - C# Efficient Solution
public int solution (int [] A){
int len = A.Length;
HashSet<int> realSet = new HashSet<int>();
HashSet<int> perfectSet = new HashSet<int>();
int i = 0;
while ( i < len)
{
realSet.Add(A[i]); //convert array to set to get rid of duplicates, order int's
perfectSet.Add(i + 1); //create perfect set so can find missing int
i++;
}
perfectSet.Add(i + 1);
if (realSet.All(item => item < 0))
return 1;
int notContains =
perfectSet.Except(realSet).Where(item=>item!=0).FirstOrDefault();
return notContains;
}
class Solution {
public int solution(int[] a) {
int smallestPositive = 1;
while(a.Contains(smallestPositive)) {
smallestPositive++;
}
return smallestPositive;
}
}
Well, this is a new winner now. At least on C# and my laptop. It's 1.5-2 times faster than the previous champion and 3-10 times faster, than most of the other solutions. The feature (or a bug?) of this solution is that it uses only basic data types. Also 100/100 on Codility.
public int Solution(int[] A)
{
bool[] B = new bool[(A.Length + 1)];
for (int i = 0; i < A.Length; i++)
{
if ((A[i] > 0) && (A[i] <= A.Length))
B[A[i]] = true;
}
for (int i = 1; i < B.Length; i++)
{
if (!B[i])
return i;
}
return A.Length + 1;
}
Simple C++ solution. No additional memory need, time execution order O(N*log(N)):
int solution(vector<int> &A) {
sort (A.begin(), A.end());
int prev = 0; // the biggest integer greater than 0 found until now
for( auto it = std::begin(A); it != std::end(A); it++ ) {
if( *it > prev+1 ) break;// gap found
if( *it > 0 ) prev = *it; // ignore integers smaller than 1
}
return prev+1;
}
int[] A = {1, 3, 6, 4, 1, 2};
Set<Integer> integers = new TreeSet<>();
for (int i = 0; i < A.length; i++) {
if (A[i] > 0) {
integers.add(A[i]);
}
}
Integer[] arr = integers.toArray(new Integer[0]);
final int[] result = {Integer.MAX_VALUE};
final int[] prev = {0};
final int[] curr2 = {1};
integers.stream().forEach(integer -> {
if (prev[0] + curr2[0] == integer) {
prev[0] = integer;
} else {
result[0] = prev[0] + curr2[0];
}
});
if (Integer.MAX_VALUE == result[0]) result[0] = arr[arr.length-1] + 1;
System.out.println(result[0]);
I was surprised but this was a good lesson. LINQ IS SLOW. my answer below got me 11%
public int solution (int [] A){
if (Array.FindAll(A, x => x >= 0).Length == 0) {
return 1;
} else {
var lowestValue = A.Where(x => Array.IndexOf(A, (x+1)) == -1).Min();
return lowestValue + 1;
}
}
I think I kinda look at this a bit differently but gets a 100% evaluation. Also, I used no library:
public static int Solution(int[] A)
{
var arrPos = new int[1_000_001];
for (int i = 0; i < A.Length; i++)
{
if (A[i] >= 0)
arrPos[A[i]] = 1;
}
for (int i = 1; i < arrPos.Length; i++)
{
if (arrPos[i] == 0)
return i;
}
return 1;
}
public int solution(int[] A) {
// write your code in Java SE 8
Set<Integer> elements = new TreeSet<Integer>();
long lookFor = 1;
for (int i = 0; i < A.length; i++) {
elements.add(A[i]);
}
for (Integer integer : elements) {
if (integer == lookFor)
lookFor += 1;
}
return (int) lookFor;
}
I tried to use recursion in C# instead of sorting, because I thought it would show more coding skill to do it that way, but on the scaling tests it didn't preform well on large performance tests. Suppose it's best to just do the easy way.
class Solution {
public int lowest=1;
public int solution(int[] A) {
// write your code in C# 6.0 with .NET 4.5 (Mono)
if (A.Length < 1)
return 1;
for (int i=0; i < A.Length; i++){
if (A[i]==lowest){
lowest++;
solution(A);
}
}
return lowest;
}
}
Here is my solution in javascript
function solution(A) {
// write your code in JavaScript (Node.js 8.9.4)
let result = 1;
let haveFound = {}
let len = A.length
for (let i=0;i<len;i++) {
haveFound[`${A[i]}`] = true
}
while(haveFound[`${result}`]) {
result++
}
return result
}
class Solution {
public int solution(int[] A) {
var sortedList = A.Where(x => x > 0).Distinct().OrderBy(x => x).ToArray();
var output = 1;
for (int i = 0; i < sortedList.Length; i++)
{
if (sortedList[i] != output)
{
return output;
}
output++;
}
return output;
}
}
You should just use a HashSet as its look up time is also constant instead of a dictionary. The code is less and cleaner.
public int solution (int [] A){
int answer = 1;
var set = new HashSet<int>(A);
while (set.Contains(answer)){
answer++;
}
return answer;
}
This snippet should work correctly.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
int result = 1;
List<int> lst = new List<int>();
lst.Add(1);
lst.Add(2);
lst.Add(3);
lst.Add(18);
lst.Add(4);
lst.Add(1000);
lst.Add(-1);
lst.Add(-1000);
lst.Sort();
foreach(int curVal in lst)
{
if(curVal <=0)
result=1;
else if(!lst.Contains(curVal+1))
{
result = curVal + 1 ;
}
Console.WriteLine(result);
}
}
}

Finding all positions of substring in a larger string in C#

I have a large string I need to parse, and I need to find all the instances of extract"(me,i-have lots. of]punctuation, and store the index of each to a list.
So say this piece of string was in the beginning and middle of the larger string, both of them would be found, and their indexes would be added to the List. and the List would contain 0 and the other index whatever it would be.
I've been playing around, and the string.IndexOf does almost what I'm looking for, and I've written some code - but it's not working and I've been unable to figure out exactly what is wrong:
List<int> inst = new List<int>();
int index = 0;
while (index < source.LastIndexOf("extract\"(me,i-have lots. of]punctuation", 0) + 39)
{
int src = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index);
inst.Add(src);
index = src + 40;
}
inst = The list
source = The large string
Any better ideas?
Here's an example extension method for it:
public static List<int> AllIndexesOf(this string str, string value) {
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
List<int> indexes = new List<int>();
for (int index = 0;; index += value.Length) {
index = str.IndexOf(value, index);
if (index == -1)
return indexes;
indexes.Add(index);
}
}
If you put this into a static class and import the namespace with using, it appears as a method on any string, and you can just do:
List<int> indexes = "fooStringfooBar".AllIndexesOf("foo");
For more information on extension methods, http://msdn.microsoft.com/en-us/library/bb383977.aspx
Also the same using an iterator:
public static IEnumerable<int> AllIndexesOf(this string str, string value) {
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
for (int index = 0;; index += value.Length) {
index = str.IndexOf(value, index);
if (index == -1)
break;
yield return index;
}
}
Why don't you use the built in RegEx class:
public static IEnumerable<int> GetAllIndexes(this string source, string matchString)
{
matchString = Regex.Escape(matchString);
foreach (Match match in Regex.Matches(source, matchString))
{
yield return match.Index;
}
}
If you do need to reuse the expression then compile it and cache it somewhere. Change the matchString param to a Regex matchExpression in another overload for the reuse case.
using LINQ
public static IEnumerable<int> IndexOfAll(this string sourceString, string subString)
{
return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index);
}
Polished version + case ignoring support:
public static int[] AllIndexesOf(string str, string substr, bool ignoreCase = false)
{
if (string.IsNullOrWhiteSpace(str) ||
string.IsNullOrWhiteSpace(substr))
{
throw new ArgumentException("String or substring is not specified.");
}
var indexes = new List<int>();
int index = 0;
while ((index = str.IndexOf(substr, index, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1)
{
indexes.Add(index++);
}
return indexes.ToArray();
}
It could be done in efficient time complexity using KMP algorithm in O(N + M) where N is the length of text and M is the length of the pattern.
This is the implementation and usage:
static class StringExtensions
{
public static IEnumerable<int> AllIndicesOf(this string text, string pattern)
{
if (string.IsNullOrEmpty(pattern))
{
throw new ArgumentNullException(nameof(pattern));
}
return Kmp(text, pattern);
}
private static IEnumerable<int> Kmp(string text, string pattern)
{
int M = pattern.Length;
int N = text.Length;
int[] lps = LongestPrefixSuffix(pattern);
int i = 0, j = 0;
while (i < N)
{
if (pattern[j] == text[i])
{
j++;
i++;
}
if (j == M)
{
yield return i - j;
j = lps[j - 1];
}
else if (i < N && pattern[j] != text[i])
{
if (j != 0)
{
j = lps[j - 1];
}
else
{
i++;
}
}
}
}
private static int[] LongestPrefixSuffix(string pattern)
{
int[] lps = new int[pattern.Length];
int length = 0;
int i = 1;
while (i < pattern.Length)
{
if (pattern[i] == pattern[length])
{
length++;
lps[i] = length;
i++;
}
else
{
if (length != 0)
{
length = lps[length - 1];
}
else
{
lps[i] = length;
i++;
}
}
}
return lps;
}
and this is an example of how to use it:
static void Main(string[] args)
{
string text = "this is a test";
string pattern = "is";
foreach (var index in text.AllIndicesOf(pattern))
{
Console.WriteLine(index); // 2 5
}
}
Without Regex, using string comparison type:
string search = "123aa456AA789bb9991AACAA";
string pattern = "AA";
Enumerable.Range(0, search.Length)
.Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; })
.Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length),StringComparison.OrdinalIgnoreCase))
.Select(searchbit => searchbit.Index)
This returns {3,8,19,22}. Empty pattern would match all positions.
For multiple patterns:
string search = "123aa456AA789bb9991AACAA";
string[] patterns = new string[] { "aa", "99" };
patterns.SelectMany(pattern => Enumerable.Range(0, search.Length)
.Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; })
.Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length), StringComparison.OrdinalIgnoreCase))
.Select(searchbit => searchbit.Index))
This returns {3, 8, 19, 22, 15, 16}
I noticed that at least two proposed solutions don't handle overlapping search hits. I didn't check the one marked with the green checkmark. Here is one that handles overlapping search hits:
public static List<int> GetPositions(this string source, string searchString)
{
List<int> ret = new List<int>();
int len = searchString.Length;
int start = -1;
while (true)
{
start = source.IndexOf(searchString, start +1);
if (start == -1)
{
break;
}
else
{
ret.Add(start);
}
}
return ret;
}
public List<int> GetPositions(string source, string searchString)
{
List<int> ret = new List<int>();
int len = searchString.Length;
int start = -len;
while (true)
{
start = source.IndexOf(searchString, start + len);
if (start == -1)
{
break;
}
else
{
ret.Add(start);
}
}
return ret;
}
Call it like this:
List<int> list = GetPositions("bob is a chowder head bob bob sldfjl", "bob");
// list will contain 0, 22, 26
Hi nice answer by #Matti Virkkunen
public static List<int> AllIndexesOf(this string str, string value) {
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
List<int> indexes = new List<int>();
for (int index = 0;; index += value.Length) {
index = str.IndexOf(value, index);
if (index == -1)
return indexes;
indexes.Add(index);
index--;
}
}
But this covers tests cases like AOOAOOA
where substring
are AOOA and AOOA
Output 0 and 3
#csam is correct in theory, although his code will not complie and can be refractored to
public static IEnumerable<int> IndexOfAll(this string sourceString, string matchString)
{
matchString = Regex.Escape(matchString);
return from Match match in Regex.Matches(sourceString, matchString) select match.Index;
}
public static Dictionary<string, IEnumerable<int>> GetWordsPositions(this string input, string[] Susbtrings)
{
Dictionary<string, IEnumerable<int>> WordsPositions = new Dictionary<string, IEnumerable<int>>();
IEnumerable<int> IndexOfAll = null;
foreach (string st in Susbtrings)
{
IndexOfAll = Regex.Matches(input, st).Cast<Match>().Select(m => m.Index);
WordsPositions.Add(st, IndexOfAll);
}
return WordsPositions;
}
Based on the code I've used for finding multiple instances of a string within a larger string, your code would look like:
List<int> inst = new List<int>();
int index = 0;
while (index >=0)
{
index = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index);
inst.Add(index);
index++;
}
I found this example and incorporated it into a function:
public static int solution1(int A, int B)
{
// Check if A and B are in [0...999,999,999]
if ( (A >= 0 && A <= 999999999) && (B >= 0 && B <= 999999999))
{
if (A == 0 && B == 0)
{
return 0;
}
// Make sure A < B
if (A < B)
{
// Convert A and B to strings
string a = A.ToString();
string b = B.ToString();
int index = 0;
// See if A is a substring of B
if (b.Contains(a))
{
// Find index where A is
if (b.IndexOf(a) != -1)
{
while ((index = b.IndexOf(a, index)) != -1)
{
Console.WriteLine(A + " found at position " + index);
index++;
}
Console.ReadLine();
return b.IndexOf(a);
}
else
return -1;
}
else
{
Console.WriteLine(A + " is not in " + B + ".");
Console.ReadLine();
return -1;
}
}
else
{
Console.WriteLine(A + " must be less than " + B + ".");
// Console.ReadLine();
return -1;
}
}
else
{
Console.WriteLine("A or B is out of range.");
//Console.ReadLine();
return -1;
}
}
static void Main(string[] args)
{
int A = 53, B = 1953786;
int C = 78, D = 195378678;
int E = 57, F = 153786;
solution1(A, B);
solution1(C, D);
solution1(E, F);
Console.WriteLine();
}
Returns:
53 found at position 2
78 found at position 4
78 found at position 7
57 is not in 153786
How is this alternative implementation?
public static class MyExtensions
{
public static int HowMany(this string str, char needle)
{
int counter = 0;
int nextIndex = 0;
for (; nextIndex != -1; )
{
nextIndex = str.IndexOf(needle, nextIndex);
if (nextIndex != -1)
{
counter++;
//step over to the next char
nextIndex++;
}
}
return counter;
}
}
you can use linq to select and enumerate all elements, then find by any string:
I've created a class:
class Pontos
{
//index on string
public int Pos { get; set; }
//caractere
public string Caractere { get; set; }
}
And use like this:
int count = 0;
var pontos = texto.Select(y => new Pontos { Pos = count++, Caractere = y.ToString() }).Where(x=>x.Caractere == ".").ToList();
then:
input string:
output list:
PS: SeForNumero is another field of my class, I need this for my own purposes, but is not necessary to this use.

Categories