C#, LINQ. How to find an element within group of elements - c#

Imagine you have int[] data = new int [] { 1, 2, 1, 1, 3, 2 }
I need sub-array with only those which conform to a condition data[i] > data[i-1] && data[i] > data[i + 1]... i.e. I need all items which stick over their immediate neighbours.
From example above I should get { 2, 3 }
Can it be done in LINQ?
Thanks

data.Where((val, index)=>(index == 0 || val > data[index - 1])
&& (index == data.Length - 1 || val > data[index + 1]));

Related

How to process list of numbers(arrays) in C#

I have a list of multiple consecutive numbers. I am trying to figure it out how to know the number of increase or decrease in relation to to past value . For example
102, 201, 198, 200
That is 2 increase (102, 201 and 198, 200) and 1 decrease (201, 198). It is a long list of number so manual is tedious. I am a beginner using C#.
There are many ways, from querying with help of Linq:
using System.Linq;
...
int[] source = new int[] { 102, 201, 198, 200 };
...
// Probably, the most generic approach
var result = source.Aggregate(
(Inc: 0, Dec: 0, prior: (int?)null),
(s, a) => (s.Inc + (s.prior < a ? 1 : 0), s.Dec + (s.prior > a ? 1 : 0), a));
Console.Write($"Increasing: {result.Inc}; decreasing: {result.Dec}");
up to good old for loop:
int Inc = 0;
int Dec = 0;
// Probably, the easiest to understand solution
for (int i = 1; i < source.Length; ++i)
if (source[i - 1] > source[i])
Dec += 1;
else if (source[i - 1] < source[i])
Inc += 1;
Console.Write($"Increasing: {Inc}; decreasing: {Dec}");
Edit: Linq Aggregate explained.
Aggregate(
(Inc: 0, Dec: 0, prior: (int?)null),
(s, a) => (s.Inc + (s.prior < a ? 1 : 0), s.Dec + (s.prior > a ? 1 : 0), a));
In order to obtain single value from a cursor, we use Aggregate.
First argument
(Inc: 0, Dec: 0, prior: (int?)null)
is the initial value (named tuple, to combine several properties in one instance). Here we have 0 increasing and decreasing and null for the previous item.
Second argument
(s, a) => (s.Inc + (s.prior < a ? 1 : 0), s.Dec + (s.prior > a ? 1 : 0), a)
Is a rule how to add a next item a to aggregated items s. We should
Increment s.Inc in case prior item is smaller than current a: s.Inc + (s.prior < a ? 1 : 0)
Increment s.Dec in case prior item is bigger than current a: s.Dec + (s.prior > a ? 1 : 0)
We should assign current item a as the next prior element.
Let's put it a bit wordy but I hope more readable:
.Aggregate(
(Inc: 0, // no increasing
Dec: 0, // no decreasing
prior: (int?)null // no prior item
),
(s, a) => ( // s - partial aggregation, a - to add item
Inc: s.Inc + (s.prior < a ? 1 : 0), // Increment Inc if required
Dec: s.Dec + (s.prior > a ? 1 : 0), // Increment Dec if required
prior: a // Set a as a prior
)
)
Hope, now it's clearer what's going under the hood of Aggregate
int[] source = new int[] { 102, 201, 198, 200 };
int Increment = 0;
int Decrement= 0;
int k;
for (k=1; k< array.length; k++)
if (array[k - 1] > array[k])
Decrement++;
else
{
if (array[k - 1] < array[k])
Increment++;
}
Console.Write("Increasing: {Increment}, decreasing: {Decrement}");
}
In this situation you can use a for loop:
for (int i = 0; i < listOfNumbers.Length; i++)
{
int currentEntry = listOfNumbers [i];
if(i > 0){
int previousEntry = listOfNumbers [i - 1];
Console.Log("Change from previous : " + (currentEntry-previousEntry));
}else{
Console.Log("No previous entry so no change can be found.");
}
}

Find the threshold value

(FF14:RR) This item can have 5 materias, 1 highlevel, 4 lowlevel.
I simplified the loops by having 3 types of materias (but i have 6, anw).
I put the materia in an item and then call Group.GetStats() to evaluate the statistics of the item then i store it in a List first checking its unicity.
Calling Group.GetStats() gives me a Dictionary with 3 caracteristics. And i want to filter the number of possibilities based on those statistics.
Example :
Stat1 - Stat2 - Stat3
(9, 7, 5)
(3, 10, 5)
(9, 7, 6)
(8, 6, 4)
(7, 6, 8)
(7, 7, 7) <-
(7, 7, 6)
(6, 6, 5)
(7, 6, 7)
All the tuples under (7, 7, 7) are useless because adding nothing more.
I already ended the algorithm to get all the possible materia combinations but i want to filter the combinations that are not useful.
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = j; k < 3; k++)
{
for (int l = k; l < 3; l++)
{
for (int m = l; m < 3; m++)
{
ItemContainer Group = new ItemContainer(735, 400, 0, 1, 4, 864, 471, 6, new string[] { "Facet Alembic", "Facet Mortar" });
Group.AddMateria(new Materia(i >= 3 ? i-3 : i));
Group.AddMateria(new Materia(j));
Group.AddMateria(new Materia(k));
Group.AddMateria(new Materia(l));
Group.AddMateria(new Materia(m));
if (DEBUG) Console.WriteLine("{" + string.Join(",", Group.GetStats()) + "}");
string tempkey = string.Join(",", Group.GetStats());
if (i >= 3)
{
if (!unicityChecker.ContainsKey(tempkey))
{
if (isAnyBetter(Group.GetStats(),betterChecker.GetStats())) // Condition to keep it
{
ContainerList_1.Add(Group);
unicityChecker.Add(tempkey, Group.GetStats());
}
}
}
else
{
/*
find the betterChecker in order to do isAnyBetter to only get the useful items
*/
if (betterChecker == null) betterChecker = Group;
else
{
if (isAllBetter(Group.GetStats(), betterChecker.GetStats())) betterChecker = Group;
}
}
}
}
}
}
}
The i < 6 sounds weird but this way i made 2 passes on the same generation of combinations.
In output of the entire algorithm (that embricks 7 of this one) i have about 10M records. I thought by removing the useless items at the first generation i could lower the size of the ouput (1Gb in json).
EDIT :
static bool isAnyBetter(Dictionary<String, int> stats1, Dictionary<String, int> stats2)
{
return stats1["craftmanship"] > stats2["craftmanship"] || stats1["control"] > stats2["control"] || stats1["cp"] > stats2["cp"];
}

Transform recursive method into non-recursive C#

I'm struggling with dynamic programming and desperately need help! I would very appreciate it. For hours I've been trying to transform a recursive method into a non-recursive one, but was unable to do that. My initial task was to write two algorithms for a recurrent equation. The first method being a recursive method, the other using a loop and storing the data.
There are two integers, n and w, and two integer arrays s[n] and p[n]. Need to find the return value of a recursive method G1(n, w) then create method G2(n, w) which would complete the same task, but it has to use loops instead of recursion.
private static int G1(int k, int r)
{
if (k == 0 || r == 0)
{
return 0;
}
if (s[k - 1] > r)
{
return G1(k - 1, r);
}
return Max(G1(k - 1, r), p[k - 1] + G1(k - 1, r - s[k - 1]));
}
I found a possible solution for C#, but I couldn't apply it for my equation:
A similar task (RECURSION)
A similar task (LOOP)
This is my code and initial data, but I can't get it to work:
n = 3;
w = 3;
s = new List<int>{ 2, 3, 8 };
p = new List<int> { 1, 3, 5 };
private static int G2(int k, int r)
{
List<Tuple<int, int, int>> data = new List<Tuple<int, int, int>>();
data.Add(new Tuple<int, int, int>(0, 0, 0));
do
{
if (data[0].Item1 == 0 || data[0].Item2 == 0)
{
data[0] = new Tuple<int, int, int>(data[0].Item1, data[0].Item2, 0);
}
else
{
if (s[data[0].Item1 - 1] > data[0].Item2)
{
data.Add(new Tuple<int, int, int>(data[0].Item1 - 1, data[0].Item2, data[0].Item3));
}
if (data[0].Item1 + 1 >= k)
{
data.Add(new Tuple<int, int, int>(data[0].Item1 - 1, data[0].Item2, data[0].Item3));
}
if (data[0].Item2 + 1 >= r)
{
data.Add(new Tuple<int, int, int>(data[0].Item1 - 1, data[0].Item2 - s[data[0].Item1 - 1], data[0].Item3 + p[data[0].Item1 - 1]));
}
}
Console.WriteLine($"DEBUG: current k: {data[0].Item1} current r: {data[0].Item2} current result: {data[0].Item3}");
data.RemoveAt(0);
} while (data.Count > 0 && data.Count(entry => entry.Item1 == k && entry.Item2 == r) <= 0);
return data.First(entry => entry.Item1 == k && entry.Item2 == r).Item3;
}
There is a common solution. You should create a 2D arry by the size of k x r. Then, loop on this array in diagonal zigzag order to fill the value (in bottom-up order, like the following image).
At the end of the filling the value of the 2d array, you will have the value of G2(k,r). You can find the implementation of G2(k,r) in the below.
int G2(int k, int r)
{
int[,] values = new int[k + 1,r + 1];
var maxDim = Max(k + 1,r + 1);
for( int h = 1 ; h < maxDim * 2 ; h++ ) {
for( int j = 0 ; j <= h ; j++ ) {
int i = h - j;
if( i <= k && j <= r && i > 0 && j > 0 ) {
if (s[i - 1] > j)
{
values[i,j] = values[i - 1, j];
}
else
{
values[i,j] = Max(values[i - 1, j], p[i - 1] + values[i - 1, j - s[i - 1]]);
}
}
}
}
return values[k , r];
}

Find number of ways in a maze non recursively

Given a matrix[n,n] I want to find out how many ways we can reach from [0,0] to [n,n] non recursively.
My approach is to
Create a stuct Node to store row, col and path travelled so far
Add node to a Queue
Iterate thru queue till not empty . Increment row, increment col. Add to Queue
Print the path if row=n, col=n
Question
Is there a different way of storing row,col and path
If n is very large, storing nodes in Queue can be a problem. How can we avoid this?
Please not I am not looking for recursive solution.
I see such questions in many interview forums and so want to know if this would be the right approach.
Below is the structure of Node and the function
struct Node
{
public int row;
public int col;
public string path;
public Node(int r, int c, string p)
{
this.row = r;
this.col = c;
this.path = p;
}
}
public static void NextMoveNonRecursive(int max)
{
int rowPos;
int colPos;
string prevPath = "";
Node next;
while (qu.Count > 0)
{
Node current = qu.Dequeue();
rowPos = current.row;
colPos = current.col;
prevPath = current.path;
if (rowPos + 1 == max && colPos + 1 == max)
{
Console.WriteLine("Path = ..." + prevPath);
TotalPathCounter++;
}
if (rowPos + 1 < max)
{
if (prevPath == "")
prevPath = current.path;
prevPath = prevPath + ">" + (rowPos + 1) + "" + (colPos);
next = new Node(rowPos + 1, colPos, prevPath);
qu.Enqueue(next);
prevPath = "";
}
if (colPos + 1 < max)
{
if (prevPath == "")
prevPath = current.path;
prevPath = prevPath + ">" + (rowPos) + "" + (colPos+1);
next = new Node(rowPos, colPos+1, prevPath);
qu.Enqueue(next);
prevPath = "";
}
}
}
Let dp[i, j] be the number of paths from [0, 0] to [i, j].
We have:
dp[0, i] = dp[i, 0] = 1 for all i = 0 to n
dp[i, j] = dp[i - 1, j] + come down from all paths to [i - 1, j]
dp[i, j - 1] + come down from all paths to [i, j - 1]
dp[i - 1, j - 1] come down from all paths to [i - 1, j - 1]
for i, j > 0
Remove dp[i - 1, j - 1] from the above sum if you cannot increase both the row and the column.
dp[n, n] will have your answer.
Given a matrix [n,n], how many ways we can reach from [0,0] to [n,n] by increasing either a col or a row?
(n*2-2) choose (n*2-2)/2
If you can only go down or right (i.e., increase row or col), it seems like a binary proposition -- we can think of 'down' or 'right' as '0' or '1'.
In an nxn matrix, every path following the down/right condition will be n*2-2 in length (for example, in a 3x3 square, paths are always length 4; in a 4x4 square, length 6).
The number of total combinations for 0's and 1's in binary numbers of x digits is 2^x. In this case, our 'x' is n*2-2, but we cannot use all the combinations since the number of 'down's or 'right's cannot exceed n-1. It seems we need all binary combinations that have an equal number of 0's and 1's. And the solution is ... tada:
(n*2-2) choose (n*2-2)/2
In Haskell, you could write the following non-recursive function to list the paths:
import Data.List
mazeWays n = nub $ permutations $ concat $ replicate ((n*2-2) `div` 2) "DR"
if you want the number of paths, then:
length $ mazeWays n
Javascript solutions with sample
var arr = [
[1, 1, 1, 0, 0, 1, 0],
[1, 0, 1, 1, 1, 1, 0],
[1, 0, 1, 0, 1, 0, 0],
[1, 1, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1]
];
function sols2(arr){
var h = arr.length,
w = arr[0].length,
i, j, current, left, top;
for(i = 0; i < h; i++){
for(j = 0; j < w; j++){
current = arr[i][j];
top = i === 0 ? 0.5 : arr[i - 1][j];
left = j === 0 ? 0.5 : arr[i][j-1];
if(left === 0 && top === 0){
arr[i][j] = 0;
} else if(current > 0 && (left > 0 || top > 0)){
arr[i][j] = (left + top) | 0;
} else {
console.log('a6');
arr[i][j] = 0;
}
}
}
return arr[h-1][w-1];
}
sols2(arr);

Finding Consecutive repetition of Elements in C# Array and Altering the element

I was given this problem
Given an int array length 3, if there is a 2 in the array immediately followed by a 3,
set the 3 element to 0.
For Example ({1, 2, 3}) → {1, 2, 0}
({2, 3, 5}) → {2, 0, 5}
({1, 2, 1}) → {1, 2, 1}
And this is my implementation.
int[] x = { 1, 2, 1 };
for (int i = 0; i < x.Length; i++)
{
if (x[i] == 2 && x[i + 1] == 3)
{
for (int j = 0; j < x.Length; j++)
{
if (x[j]==3)
{
x[j] = 0;
}
}
}
}
foreach (int i in x)
{
Console.Write(i);
}
I got zero as result. Can you help me to find where I am at mistake. I can't figure it out because the lecturer didn't gave any explanation in details.
You do not need all these loops: with the length of 3, you need to perform only two checks, like this:
if (x[0]==2 && x[1]==3) x[1] = 0;
if (x[1]==2 && x[2]==3) x[2] = 0;
For arrays of arbitrary size, you could use a single loop:
for (var i = 0 ; i < x.Length-1 ; i++) {
if (x[i]==2 && x[i+1]==3) x[i+1] = 0;
}
In your code, you have a proper check: if (x[i] == 2 && x[i + 1] == 3) However, there are 2 things you could improve on.
1) If you're going to do x[i + 1] you need to make sure that i can never be the last element of the array, because the + 1 will overflow the array. So instead of i < x.Length in the for loop, try i < x.Length - 1. It seems like duct taping, but there isn't really a better way (none I know of).
2) If the condition is true, you then have a for that will find and replace EVERY 3 in the array with a 0, regardless of if the 3 is preceded by a 2. You already know that x[i] is 2 and x[i + 1] is 3 (as determined by the if that we know at this point must be true), so the index of the 3 to be replaced is i + 1, thus: x[i + 1] = 0; No loop needed.
You can do it with one loop.
// In the test part of the for loop, use ' i < x.Length - 1'
// so you don't evaluate the last element + 1 and get an IndexOutOfRangeException
for (int i = 0; i < x.Length - 1; i++)
{
if (x[i] == 2 && x[i + 1] == 3)
x[i + 1] = 0;
}

Categories

Resources