LINQ execution flow (homework) - c#

I don't understand the order of execution in the following code. Here the numbers that satisfied the first Where clause are (4, 10, 3, 7), and the numbers that satisfied the second Where clause are 2 and 1, after that we have function Aggregate that subtract them and make one element from both.
My question is what is the flow of execution here - (1) Where is executed with c/3 > 0 for all the elements and after that (2) Where or (1) first clause is executed for one element and its passed to (2) and from there to aggregate - when I print the values I cannot get value of x to be 28 on paper with both approaches also I cannot debug linq statement. Thanks for any help in advance.
var ints = new int[] { 2, 4, 1, 10, 3, 7 };
var x = ints
.Where(c => c / 3 > 0) <-- (1)
.Select(s2 => s2 + ints
.Where(c => c / 3 == 0) <-- (2)
.Aggregate((f, s) => f - s))
.Sum();

The same statement can be written as follows:
var ints = new int[] { 2, 4, 1, 10, 3, 7 };
var x = ints
.Where(c =>
{
Console.WriteLine($"1 Where for number: {c}");
return c / 3 > 0;
}) //< --(1)
.Select(s2 => s2 + ints
.Where(c =>
{
Console.WriteLine($"2 Where for number: {c}");
return c / 3 == 0;
}) // < --(2)
.Aggregate((f, s) =>
{
Console.WriteLine($"Aggregate: f: {f} s: {s}");
return f - s;
}))
.Sum();
In this every shorthand lambda expression can be written as a complete anonymous method with a method body. You just need to use the { .. } parentheses. Inside them you can write multiple statements. If you check the documentation for Where you can see that it expects (in your case) a Func<int, bool> as input parameter. That means that you pass an int inside and return a bool. This is why you need to write the explicit return statement as I did: return c / 3 > 0;
If you now insert there a debug output to the console you will get a written proof and insight into the execution of the entire code compartment.
The resulting output looks like the following:
1 Where for number: 2
1 Where for number: 4
2 Where for number: 2
2 Where for number: 4
2 Where for number: 1
Aggregate: f: 2 s: 1
2 Where for number: 10
2 Where for number: 3
2 Where for number: 7
1 Where for number: 1
1 Where for number: 10
2 Where for number: 2
2 Where for number: 4
2 Where for number: 1
Aggregate: f: 2 s: 1
2 Where for number: 10
2 Where for number: 3
2 Where for number: 7
1 Where for number: 3
2 Where for number: 2
2 Where for number: 4
2 Where for number: 1
Aggregate: f: 2 s: 1
2 Where for number: 10
....
....

ints
.Where(c => c / 3 == 0) // (2,1)
.Aggregate((f, s) => f - s) // 2-1
evaluates to 1
Therefore your query can be switched to:
var ints = new int[] { 2, 4, 1, 10, 3, 7 };
var x = ints
.Where(c => c / 3 > 0) // (4,10,3,7)
.Select(s2 => s2 + 1) // (5,11,4,8)
.Sum(); // 28

Related

Get all subset sof given array with 'cost' restiction

I have a set of typed elements and price for each type
var array = new []
{
new Elem(0, Types.LowCost),
new Elem(1, Types.MediumCost),
new Elem(2, Types.MediumCost),
new Elem(3, Types.HightCost),
}
And prices: LowCost - 3, MediumCost - 5, HightCost - 9
How would you find all possible unique combinations of elements with restriction "sum of costs for all elements doesn't exceed a restriction"?
For example for MaxCost = 13 I expect
Elem(0) //cost 3
Elem(1) // 5
Elem(2) // 5
Elem(3) // 9
Elem(0), Elem(1) //cost 3+5=8
Elem(0), Elem(2) // 3+5=8
Elem(0), Elem(3) // 3+9=12
Elem(1), Elem(2) // 5+5 = 10
Elem(0), Elem(1), Elem(2) // cost 13
Given a dictionary of costs:
public Dictionary<Types, int> costs = new Dictionary<Types, int>()
{
{ Types.LowCost, 3 },
{ Types.MediumCost, 5 },
{ Types.HightCost, 9 },
};
I can do this:
var query =
from n in Enumerable.Range(0, 1 << array.Length).Skip(1)
let combination = array.Where((x, i) => ((n >> i) & 1) == 1).ToArray()
let cost = combination.Select(x => costs[x.Type]).Sum()
where cost <= 13
select String.Join(", ", combination.Select(x => x.Id));
That gives me:
0
1
0, 1
2
0, 2
1, 2
0, 1, 2
3
0, 3

C# Soft Number By Difference From Input

I have the following code. Please help me get my desired output. I have a list of numbers then I have input value which is 4. I want that my list will be sorted based on 0 difference first then the rest will be ascending. For example in my list there are 4s. My input is 4 so I want to sort those numbers where number item - input value=0 (4-4=0).
C#
static void Main(string[] args)
{
var numbers = new List<int> { 1, 2, 3, 4, 4, 5, 6, 7, 4, 8, 1, 4 };
var sortedNumbers = numbers.OrderBy(x => x - 4 == 0);
foreach (var item in sortedNumbers)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
OUTPUT
1
2
3
5
6
7
8
1
4
4
4
4
Desired Output
4
4
4
4
1
1
2
3
5
6
7
8
Instead of numbers.OrderBy(x => x - 4 == 0) you need to use OrderByDescending, because true is "more" than false and you want them first. You also want to sort the rest by their value:
var sortedNumbers = numbers.OrderByDescending(x => x == 4).ThenBy(x => x);
If you can't remember if you need to use OrderBy or OrderByDescending use:
var sortedNumbers = numbers.OrderBy(x => x == 4 ? 0 : 1).ThenBy(x => x);
You can achieve your desired output by using a ternary expression inside the OrderBy lambda :
static void Main(string[] args)
{
var numbers = new List<int> { 1, 2, 3, 4, 4, 5, 6, 7, 4, 8, 1, 4 };
var sortedNumbers = numbers.OrderBy(x => x==4? int.MinValue: x);
foreach (var item in sortedNumbers)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
output :
4
4
4
4
1
1
2
3
5
6
7
8
Edit : in case you have zero or negative number in your list, your number will be order as follow : first, exact match, then ascending. For example : { -1, 0, 0, -12, 1, 2, 3, 4, 4, 5, 6, 7, 4, 8, 1, 4 }
the result will be the following :
4
4
4
4
-12
-1
0
0
1
1
2
3
5
6
7
8

Linq query to select records based on most recent sum

I'm writing a method that selects customer records based on a group by with the most recent purchase total equal (passed to the method).
I did some search and nothing showed up that helps me to achieve the desired output.
customerList.GroupBy(x=> x.CustomerID },
(key, result) =>
{
var orderedList = result.OrderByDescending(c => c.Date).ToList();
return new Customer
{
CustomerID = orderedList.First().CustomerID,
PurchaseID = orderedList.First().PurchaseID,
Price = orderedList.First().Price,
};
});
CUSTOMERID
PURCHACEID
PRICE
DATE
1
11
235
01-03-2021
1
12
230
01-03-2021
1
14
235
05-04-2021
1
15
535
06-04-2021
1
16
230
07-04-2021
If I'm looking for most recent total purchase price of 1000, I should get
CUSTOMERID
PURCHACEID
PRICE
DATE
1
14
235
05-04-2021
1
15
535
06-04-2021
1
16
230
07-04-2021
You probably need to produce a separate list with the cumulative sums. You can then use TakeWhile to take items until some condition is reached
var list = new[] { 1, 2, 3, 4, 5 };
var sum = 0;
var cummulativeSums = list.Select(v => sum += v).ToList();
var result= list.TakeWhile((_, index) => cummulativeSums[index] < 7).ToList();
// 1, 2, 3
Or you could do it all in one go by creating intermediate pair of values.
var list = new[] { 1, 2, 3, 4, 5 };
var sum = 0;
var result = list.Select(value => (sum += value, value))
.TakeWhile(pair => pair.Item1 < 7)
.Select(pair => pair.value)
.ToList();

Optimum Cutting of Rod with Length n into any of 3 possibly 4 sizes

I am not sure if I am in the correct area on stack - so my apologies first ..
I need to know how I can calculate all possible combinations (for 3 different fixed lengths) that can fit into a Rod of n length.
So for example if I have 3 fixed lengths of 8, 10, 12 and a Rod of variable Length n say 50'; I want to know all the possible cuts that I can make.
Using Microsoft Solver Foundation:
const int rodLength = 50;
const int lengthA = 8, lengthB = 10, lengthC = 12;
var solver = SolverContext.GetContext();
var model = solver.CreateModel();
var decisionA = new Decision(Domain.IntegerNonnegative, "A");
model.AddDecision(decisionA);
var decisionB = new Decision(Domain.IntegerNonnegative, "B");
model.AddDecision(decisionB);
var decisionC = new Decision(Domain.IntegerNonnegative, "C");
model.AddDecision(decisionC);
model.AddGoal("Goal", GoalKind.Minimize,
rodLength - (decisionA * lengthA) - (decisionB * lengthB) - (decisionC * lengthC));
int maxItems = (rodLength / new [] { lengthA, lengthB, lengthC }.Min());
model.AddConstraint("MaxItems", decisionA + decisionB + decisionC < maxItems);
var solution = solver.Solve();
Console.WriteLine("A " + decisionA.GetDouble());
Console.WriteLine("B " + decisionB.GetDouble());
Console.WriteLine("C " + decisionC.GetDouble());
where we trying to minimize the difference between the rod length and the sum of the items constraining the number of items (in your case max 50 / 8 = 6 items).
Here is sample of code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication104
{
class Program
{
static void Main(string[] args)
{
string max = "111111";
int size = 50;
List<List<int>> numbers = CountModThree(max,size);
Print(numbers);
Console.ReadLine();
}
static List<List<int>> CountModThree(string max,int size)
{
List<List<int>> results = new List<List<int>>();
List<int> newMod3 = new List<int>() {0};
while(true)
{
int length = newMod3.Select(x => x == 0 ? 8 : x == 1 ? 10 : 12).Sum();
if (length <= size) results.Add(newMod3);
if (string.Join("", newMod3) == max) break;
newMod3 = AddOne(newMod3);
}
return results;
}
static List<int> AddOne(List<int> number)
{
List<int> newNumber = new List<int>();
newNumber.AddRange(number);
int carry = 1;
for (int i = number.Count - 1; i >= 0; i--)
{
int digit = newNumber[i] + carry;
if (digit == 3)
{
newNumber[i] = 0;
carry = 1;
}
else
{
newNumber[i] = digit;
carry = 0;
break;
}
}
if (carry == 1) newNumber.Insert(0, 0);
return newNumber;
}
static void Print(List<List<int>> numbers)
{
foreach(List<int> number in numbers)
{
Console.WriteLine("string : '{0}', Total Length : '{1}, Number 8ft sections : '{2}', Number 10ft sections : '{3}', Number 12ft sections : '{4}'",
string.Join("", number),
number.Select(x => x == 0 ? 8 : x == 1 ? 10 : 12).Sum(),
number.Where(x => x == 0).Count(),
number.Where(x => x == 1).Count(),
number.Where(x => x == 2).Count()
);
}
}
}
}
You want to get all partitions of n into predefined integer pieces. Simple approach is using recursion.
Python code gives all possible solutions, ignoring summands order due to last index usage. So 8 8 8 8 8 10 and 8 8 10 8 8 8 variants are considered the same. If you need to distinguish them, just remove last argument and start loop from 0.
def solution(sum, lst, last, sol):
if sum == 0:
print(sol)
return
for i in range(last, len(lst)):
if lst[i] <= sum:
solution(sum - lst[i], lst, i, sol + " " + str(lst[i]))
return
solution(50, [8,10,12], 0, "")
8 8 8 8 8 10
8 8 10 12 12
8 10 10 10 12
10 10 10 10 10
If you need also solutions with smaller overall length (if n is unreachable) - remember solutions with small rest of sum, then use ones with the smallest rest. Quick-made example:
dict = [[] for i in range(10)]
def solution(sum, lst, last, sol):
if sum == 0:
print(sol)
return
if sum < 10:
dict[sum].append(sol)
for i in range(last, len(lst)):
if lst[i] <= sum:
solution(sum - lst[i], lst, i, sol + " " + str(lst[i]))
return
solution(50, [5, 13 , 21], 0, "")
for i in range(1, len(dict)):
if len(dict[i]) > 0:
print(dict[i])
break
5 5 5 5 5 5 5 5 5 5 #exact
[' 5 5 5 13 21', ' 5 5 13 13 13'] #inexact but close
There is also non-recursive method: make table A[0..n] and fill it with items (note that table might be huge!)
def tablecuts(sum, lst):
cuts = [[] for i in range(sum+1)]
cuts[0].append('*')
for item in lst:
for i in range(0, sum - item + 1):
if len(cuts[i]) > 0:
for j in cuts[i]:
cuts[i+item].append(j+" " + str(item))
for i in range(len(cuts)):
print(i, cuts[i])
tablecuts(13, [2,5,7])
0 ['*']
1 []
2 ['* 2']
3 []
4 ['* 2 2']
5 ['* 5']
6 ['* 2 2 2']
7 ['* 2 5', '* 7']
8 ['* 2 2 2 2']
9 ['* 2 2 5', '* 2 7']
10 ['* 2 2 2 2 2', '* 5 5']
11 ['* 2 2 2 5', '* 2 2 7']
12 ['* 2 2 2 2 2 2', '* 2 5 5', '* 5 7']
13 ['* 2 2 2 2 5', '* 2 2 2 7']

How to exchange string content in a text file in C#?

I have a text file as follows:
1 ... 3 4 2
2 ... 3 21 4
3 ... 6 4 21 15
4 ... 14 21 12
I want to edit these strings, so that numbers after dotted parts to be splitted corresponding to the first number of each string. For example,
1
2 1
3 1 2
4 1 2 3
...
21 3 4
How can I do this?
Note: I obtain the first number group from a text file and edit it string by string. After that, I have written edited strings to the text file. In light of this, sample part of my code to obtain the first number group is provided as below:
for (var i = 0; i < existingLines.Length; i++)
{
var split = existingLines[i].Split('\t');
var act = i - 1;
var sc1 = int.Parse(split[6]);
var sc2 = int.Parse(split[7]);
appendedLines.Add(string.Format("{0} {1} {2}", act, sc1, sc2));
}
This LINQ code should get you started
string path = "c:\\temp\\test.txt";
using (var sr = new StreamReader(path))
{
var lines = new List<IEnumerable<int>>();
while (!sr.EndOfStream)
{
lines.Add(sr.ReadLine().Split(new[] { '.', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(x => int.Parse(x)));
}
foreach (var node in lines.SelectMany(x => x).Distinct().OrderBy(x => x))
{
var predecessors = lines.Where(x => x.Skip(1).Contains(node))
.Select(x => x.First())
.OrderBy(x => x);
Console.WriteLine(node + " " + string.Join(" ", predecessors));
}
}
Output
2 1
3 1 2
4 1 2 3
6 3
12 4
14 4
15 3
21 2 3 4

Categories

Resources