Find inconsistent and consecutive objects from List in C# - c#

I'm having trouble with getting a consecutive and nonconsecutive number from list. I'm sure it's pretty simple, but i can't get it.
If consecutiveNum=2, then if result from before last and last is equal, i need to throw an exception.
If nonConsecutiveNum=4, then if from 10 pieces there are 4 with same result, i need to throw an exception.
I'm trying with nested loops and couple checks, but i didn't succeeded at all. Same is for both cases, i tried a couple solutions with System.LINQ, but again i don't get the result i need.
Thanks in advance to all of you!
int consecutiveNum = 2;
int nonConsecutiveNum = 4;
int counter = 1;
var sensInfo = new ResultInfo()
{
Product = CurrentLot.Info.Product,
Result = code
};
if (consecutiveNum > 0)
{
for (int i = ListSensors.Count + 1; i >= 0; i--)
{
if (sensInfo.Result == ListSensors[i].Result)
{
counter++;
if (counter >= consecutiveNum)
{
throw new Exception("Consecutive num");
}
}
}
}
if (nonConsecutiveNum > 0)
{
for (int i = 0; i < ListSensors.Count; i++)
{
for (int j = i + 2; j < ListSensors.Count - 2; j++)
{
if (ListSensors[i].Result == ListSensors[i+1].Result)
continue;
if (ListSensors[i].Result == ListSensors[j].Result)
{
counter++;
if (counter >= nonConsecutiveNum)
{
throw new Exception("NonConsecutive num");
}
}
}
}
}

// consecutiveNum
for (int i = ListSensors.Count - 1; i >= 0; i--)
{
if (sensInfo.Result == ListSensors[i].Result)
{
counter++;
if (counter >= consecutiveNum)
{
throw new Exception("Consecutive num");
}
}
else
{
counter = 1;
}
}
// nonConsecutiveNum
IDictionary<int, int> resultCountDictionary = new Dictionary<int,int>();
foreach (var listSensor in ListSensors)
{
if (resultCountDictionary.ContainsKey(listSensor.Result))
{
resultCountDictionary[listSensor.Result] = resultCountDictionary[listSensor.Result] + 1;
if (resultCountDictionary[listSensor.Result] >= nonConsecutiveNum)
{
throw new Exception();
}
}
else
{
resultCountDictionary.Add(listSensor.Result, 1);
}
}

Consecutive:
Using MoreLinq's Window function:
ListSensors.Window(consecutiveNum).Any(x => x.Distinct().Count() == 1);
Nonconsecutive:
ListSensors.Any(x => ListSensors.Count(s => s == x) >= nonConsecutiveNum);

Related

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

Implementing and using MinMax with four in row (connect4) game

I'm trying to implement the MinMax algorithm for four in a row (or connect4 or connect four) game.
I think I got the idea of it, it should build a tree of possible boards up to a certain depth, evaluate them and return their score, then we just take the max of those scores.
So, aiChooseCol() checks the score of every possible column by calling MinMax() and returns the column with the max score.
Now I wasn't sure, is this the right way to call MinMax()?
Is it right to check temp = Math.Max(temp, 1000);?
I still haven't made the heuristic function but this should at least recognize a winning column and choose it, but currently it just choose the first free column from the left... I can't figure out what am I doing wrong.
private int AiChooseCol()
{
int best = -1000;
int col=0;
for (int i = 0; i < m_Board.Cols; i++)
{
if (m_Board.CheckIfColHasRoom(i))
{
m_Board.FillSignInBoardAccordingToCol(i, m_Sign);
int t = MinMax(5, m_Board, board.GetOtherPlayerSign(m_Sign));
if (t > best)
{
best = t;
col = i;
}
m_Board.RemoveTopCoinFromCol(i);
}
}
return col;
}
private int MinMax(int Depth, board Board, char PlayerSign)
{
int temp=0;
if (Depth <= 0)
{
// return from heurisitic function
return temp;
}
char otherPlayerSign = board.GetOtherPlayerSign(PlayerSign);
char checkBoard = Board.CheckBoardForWin();
if (checkBoard == PlayerSign)
{
return 1000;
}
else if (checkBoard == otherPlayerSign)
{
return -1000;
}
else if (!Board.CheckIfBoardIsNotFull())
{
return 0; // tie
}
if (PlayerSign == m_Sign) // maximizing Player is myself
{
temp = -1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Max(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
else
{
temp = 1000;
for (int i = 0; i < Board.Cols; i++)
{
if (Board.FillSignInBoardAccordingToCol(i, PlayerSign)) // so we don't open another branch in a full column
{
var v = MinMax(Depth - 1, Board, otherPlayerSign);
temp = Math.Min(temp, v);
Board.RemoveTopCoinFromCol(i);
}
}
}
return temp;
}
Some notes:
FillSignInBoardAccordingToCol() returns a boolean if it was successful.
The board type has a char[,] array with the actual board and signs of the players.
This code is in the AI Player class.
So I decided to write my own MinMax Connect 4. I used the depth to determine the value of a win or loss so that a move that gets you closer to winning or blocking a loss will take precedence. I also decide that I will randomly pick the move if more than one has the same heuristic. Finally I stretched out the depth to 6 as that's how many moves are required to find possible win paths from the start.
private static void Main(string[] args)
{
var board = new Board(8,7);
var random = new Random();
while (true)
{
Console.WriteLine("Pick a column 1 -8");
int move;
if (!int.TryParse(Console.ReadLine(), out move) || move < 1 || move > 8)
{
Console.WriteLine("Must enter a number 1-8.");
continue;
}
if (!board.DropCoin(1, move-1))
{
Console.WriteLine("That column is full, pick another one");
continue;
}
if (board.Winner == 1)
{
Console.WriteLine(board);
Console.WriteLine("You win!");
break;
}
if (board.IsFull)
{
Console.WriteLine(board);
Console.WriteLine("Tie!");
break;
}
var moves = new List<Tuple<int, int>>();
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(2, i))
continue;
moves.Add(Tuple.Create(i, MinMax(6, board, false)));
board.RemoveTopCoin(i);
}
int maxMoveScore = moves.Max(t => t.Item2);
var bestMoves = moves.Where(t => t.Item2 == maxMoveScore).ToList();
board.DropCoin(2, bestMoves[random.Next(0,bestMoves.Count)].Item1);
Console.WriteLine(board);
if (board.Winner == 2)
{
Console.WriteLine("You lost!");
break;
}
if (board.IsFull)
{
Console.WriteLine("Tie!");
break;
}
}
Console.WriteLine("DONE");
Console.ReadKey();
}
private static int MinMax(int depth, Board board, bool maximizingPlayer)
{
if (depth <= 0)
return 0;
var winner = board.Winner;
if (winner == 2)
return depth;
if (winner == 1)
return -depth;
if (board.IsFull)
return 0;
int bestValue = maximizingPlayer ? -1 : 1;
for (int i = 0; i < board.Columns; i++)
{
if (!board.DropCoin(maximizingPlayer ? 2 : 1, i))
continue;
int v = MinMax(depth - 1, board, !maximizingPlayer);
bestValue = maximizingPlayer ? Math.Max(bestValue, v) : Math.Min(bestValue, v);
board.RemoveTopCoin(i);
}
return bestValue;
}
public class Board
{
private readonly int?[,] _board;
private int? _winner;
private bool _changed;
public Board(int cols, int rows)
{
Columns = cols;
Rows = rows;
_board = new int?[cols, rows];
}
public int Columns { get; }
public int Rows { get; }
public bool ColumnFree(int column)
{
return !_board[column, 0].HasValue;
}
public bool DropCoin(int playerId, int column)
{
int row = 0;
while (row < Rows && !_board[column,row].HasValue)
{
row++;
}
if (row == 0)
return false;
_board[column, row - 1] = playerId;
_changed = true;
return true;
}
public bool RemoveTopCoin(int column)
{
int row = 0;
while (row < Rows && !_board[column, row].HasValue)
{
row++;
}
if (row == Rows)
return false;
_board[column, row] = null;
_changed = true;
return true;
}
public int? Winner
{
get
{
if (!_changed)
return _winner;
_changed = false;
for (int i = 0; i < Columns; i++)
{
for (int j = 0; j < Rows; j++)
{
if (!_board[i, j].HasValue)
continue;
bool horizontal = i + 3 < Columns;
bool vertical = j + 3 < Rows;
if (!horizontal && !vertical)
continue;
bool forwardDiagonal = horizontal && vertical;
bool backwardDiagonal = vertical && i - 3 >= 0;
for (int k = 1; k < 4; k++)
{
horizontal = horizontal && _board[i, j] == _board[i + k, j];
vertical = vertical && _board[i, j] == _board[i, j + k];
forwardDiagonal = forwardDiagonal && _board[i, j] == _board[i + k, j + k];
backwardDiagonal = backwardDiagonal && _board[i, j] == _board[i - k, j + k];
if (!horizontal && !vertical && !forwardDiagonal && !backwardDiagonal)
break;
}
if (horizontal || vertical || forwardDiagonal || backwardDiagonal)
{
_winner = _board[i, j];
return _winner;
}
}
}
_winner = null;
return _winner;
}
}
public bool IsFull
{
get
{
for (int i = 0; i < Columns; i++)
{
if (!_board[i, 0].HasValue)
return false;
}
return true;
}
}
public override string ToString()
{
var builder = new StringBuilder();
for (int j = 0; j < Rows; j++)
{
builder.Append('|');
for (int i = 0; i < Columns; i++)
{
builder.Append(_board[i, j].HasValue ? _board[i,j].Value.ToString() : " ").Append('|');
}
builder.AppendLine();
}
return builder.ToString();
}
}

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.

Count similar adjacent items in List<string>

I'm trying to find similar adjacent items in List and count its number, e.g.:
List<string> list = new List<string> {"a", "a", "b", "d", "c", "c"};
Desired Output:
a = 2, c = 2
What I've done is use for loop to iterate over each element of the list and to see whether it has similar adjacent element, but understandably it gives ArgumentOutOfRangeException() because I don't know how to keep track of the position of the iterator so that it doesn't go out of bounds. Here's what I've done:
for (int j = 0; j < list.Count; j++)
{
if (list[j] == "b")
{
if ((list[j + 1] == "b") && (list[j - 1] == "b"))
{
adjacent_found = true;
}
}
}
Having said that, if there's another easier way to find similar adjacent elements in a List other than using for loop iteration, please advise. Thanks.
You can do something like this:
static IEnumerable<Tuple<string, int>> FindAdjacentItems(IEnumerable<string> list)
{
string previous = null;
int count = 0;
foreach (string item in list)
{
if (previous == item)
{
count++;
}
else
{
if (count > 1)
{
yield return Tuple.Create(previous, count);
}
count = 1;
}
previous = item;
}
if (count > 1)
{
yield return Tuple.Create(previous, count);
}
}
for (int i= 0; i < list.Count; i++)
{
for (int j = i + 1; j < list.Count; j++)
{
if (list[i] == list[j])
{
adjacent_found = true;
count++;
}
}
}
Check this:
Dictionary<char,int> dic=new Dictionary<char,int>();
for(int i=1;i<list.count;i++)
{
if(list[i]==list[i-1])
{
if(dic.ContainsKey(list[i]))
{
dic[list[i]]+=1;
}
else
{
dic.Add(list[i],2)
}
}
}
To avoid ArgumentOutOfRangeException use for (int j = 1; j < list.Count - 1; j++). Desired answer can't be achieved this way. Try this:
IEnumerable<Adjacent> CountAdjacents(List<string> source)
{
var result = new List<Adjacent>();
for (var i = 0; i < source.Count() - 1; i++)
{
if (source[i] == source[i + 1])
{
if (result.Any(x => x.Word == source[i]))
{
result.Single(x => x.Word == source[i]).Quantity++;
}
else
result.Add(new Adjacent
{
Word = source[i],
Quantity = 2
});
}
}
return result;
}
class Adjacent
{
public string Word;
public int Quantity;
}
Maintain an int array of 256 size, initialized to 1. Run a loop [O(n)] for i=0 to i-2, compare each char with the next char. If same then find the ascii value of the char and increment the corresponding value in array.
Hope this helps!

C# InsertionSort 1xforeach 2xfor

I want to create an insertionsort but I can't get any further.
I solved it on my way until I get out of bounds, in the second "for-command" which I can't solve. I'm not sure if I am on the right way, but I want to keep the solution simple.
int arrayzähler = 0;
int[] Speicherarray = new int[randomarray.Length];
//ausgabearray[1] = randomarray[1]; //für vergleich
foreach (int wert in randomarray)
{
if (wert == randomarray[0])
{
Speicherarray[0] = wert;
ausgabearray[0] = wert;
arrayzähler++;
continue; // erster wert = ausgabearray[0]
}
arrayzähler++;
for (int i = arrayzähler - 1; i >= arrayzähler - 1; i--)
{
for (int a = arrayzähler - 2; a >= arrayzähler - 2; a--)
{
if (Speicherarray[i] < Speicherarray[a])
{
Speicherarray[a] = Speicherarray[a + 1];
}
else if (Speicherarray[i] >= Speicherarray[a])
{
Speicherarray[a] = wert;
ausgabearray[i] = Speicherarray[i];
}
}
}
}
This is exact coding for insertion sort,
public void Sort(int[] collection)
{
int inner, temp;
for (int i = 1; i < collection.Length; i++)
{
temp = collection[i];
inner = i;
while (inner > 0 && collection[inner - 1] >= temp)
{
collection[i] = collection[inner - 1];
--inner;
}
collection[inner] = temp;
}
Console.WriteLine("Printing Insertion Sorted Items");
Print();
}

Categories