How to find all possible values of 100 dollar bill [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
banknotes provided = 10 Dollar, 50 Dollar, 100 Dollar
Expected Result for 100 dollar bill with above bank notes.
I want to show the denomination exactly like below
5 x 10 + 1x 50
2 x 50
1 x 100
10 x 10
As you can see all the banknotes denomination total to 100 above

Let's split the problem in two:
Solve the exchange problem of total given notes (in descending order), starting from nominal at index.
Provide the solution in required format
Code:
private static IEnumerable<int[]> Solutions(int total, int[] notes, int index) {
int value = notes[index];
if (index == notes.Length - 1) {
if (total % value == 0)
yield return new int[] { total / value };
}
else
for (int i = total / value; i >= 0; --i)
foreach (int[] rest in Solutions(total - value * i, notes, index + 1))
yield return rest.Prepend(i).ToArray();
}
private static IEnumerable<string> Solve(int total, int[] notes) {
var items = notes.OrderByDescending(item => item).ToArray();
foreach (int[] solution in Solutions(total, items, 0))
yield return string.Join(" + ", solution
.Zip(items, (count, note) => (count, note))
.Where(pair => pair.count > 0)
.Select(pair => $"{pair.count} x {pair.note}"));
}
Demo:
int total = 170;
int[] notes = new int[] {10, 50, 100};
Console.Write(string.Join(Environment.NewLine, Solve(total, notes)));
Output:
1 x 100 + 1 x 50 + 2 x 10
1 x 100 + 7 x 10
3 x 50 + 2 x 10
2 x 50 + 7 x 10
1 x 50 + 12 x 10
17 x 10
Fiddle

Here is another (way less compact and cool than Dmitry's) solution, that uses recursion as you said. Basically I create a tree for each possible sum of the available banknotes that starts with the given amount at the root. For example, for your given amount of 100, and the given notes 10, 50, 100, I create the following pictured trees (and more), where the leaf values represent the individual banknotes that make up the total amount.
The leaf values then get transformed to your output, and possible duplicates (since different trees can be created from the same bank notes) are not printed out.
The following input:
int[] availableBanknotes = { 10, 50, 100 };
int amount = 100;
SolveRecursive(amount, availableBanknotes);
prints out:
10 x 10
1 x 50 + 5 x 10
2 x 50
1 x 100
The following input:
int[] availableBanknotes = { 10, 50, 100 };
int amount = 170;
SolveRecursive(amount, availableBanknotes);
prints out:
17 x 10
1 x 50 + 12 x 10
2 x 50 + 7 x 10
1 x 100 + 7 x 10
3 x 50 + 2 x 10
1 x 100 + 1 x 50 + 2 x 10
Here is the code:
private static List<string> Solutions = new List<string>();
private static void SolveRecursive(int amount, int[] availableBanknotes)
{
List<int> denomination = new List<int>();
for (int i = 0; i < availableBanknotes.Length; i++)
{
if (amount >= availableBanknotes[i])
{
ProvidedBanknotes(amount, availableBanknotes[i], availableBanknotes, new List<int>(denomination));
}
}
Solutions = new List<string>();
}
private static void ProvidedBanknotes(int amount, int currentBankNote, int[] availableBanknotes, List<int> denomination)
{
amount = amount - currentBankNote;
denomination.Add(currentBankNote);
if (amount == 0)
{
PrintSolution(denomination, availableBanknotes);
return;
}
for (int i = 0; i < availableBanknotes.Length; i++)
{
if(amount >= availableBanknotes[i])
{
ProvidedBanknotes(amount, availableBanknotes[i], availableBanknotes, new List<int>(denomination));
}
}
}
private static void PrintSolution(List<int> denomination, int[] availableBanknotes)
{
string solution = "";
for(int i = availableBanknotes.Length - 1; i >= 0; i--)
{
int currentVal = availableBanknotes[i];
int count = denomination.Where(temp => temp.Equals(currentVal))
.Select(temp => temp)
.Count();
if (count != 0)
{
if(solution.Equals(""))
{
solution = $"{count} x {currentVal}";
}
else
{
solution = solution + $" + {count} x {currentVal}";
}
}
}
if(!Solutions.Contains(solution))
{
Solutions.Add(solution);
Console.WriteLine(solution);
}
}

Given
var notes = new[] { 10, 50, 100 };
var total = 100;
You can use a LINQ Extension Method to create all possible combinations of notes and filter them to just combinations that could be used to create the total. I sort the notes in the combination descending so that the final answer will be output in descending order:
var possibleCombos = notes.Where(n => n <= total)
.AllCombinations()
.Select(c => c.OrderByDescending(n => n).ToList())
.Where(c => c.Sum() <= total && c.Aggregate(total-c.Sum(), (r, n) => r % n) == 0)
.OrderBy(c => c.Last());
While it doesn't apply to the example, the Aggregate expression ensures that impossible combinations aren't selected, such as trying to make { 50, 20 } yield 100.
For each possible combination, you can start with the total and then take away one of each note to ensure at least one of each note is in the answer. It then computes the number of additional notes needed for each denomination, starting with the largest. For each combination it outputs the number of each note in the format requested:
foreach (var combo in possibleCombos) {
var numberOfNotes = Enumerable.Repeat(1, combo.Count).ToList(); // one of each denomination
var remainder = total - combo.Sum(); // start by taking away one of each denomination
for (int j1 = 0; j1 < combo.Count; ++j1) {
numberOfNotes[j1] += remainder / combo[j1]; // take away all possible of each denomination
remainder = remainder % combo[j1];
}
Console.WriteLine(String.Join(" + ", numberOfNotes.Select((numberOfNote, j1) => $"{numberOfNote} x {combo[j1]}")));
}
The extension method is defined as:
public static class IEnumerableExt {
public static IEnumerable<IEnumerable<T>> AllCombinations<T>(this IEnumerable<T> start) {
IEnumerable<IEnumerable<T>> HelperCombinations(IEnumerable<T> items) {
if (items.IsEmpty())
yield return items;
else {
var head = items.First();
var tail = items.Skip(1);
foreach (var sequence in HelperCombinations(tail)) {
yield return sequence; // Without first
yield return sequence.Prepend(head);
}
}
}
return HelperCombinations(start).Skip(1); // don't return the empty set
}
}
NOTE: This only produces one possible solution for each combination of bills, the one that uses the maximum possible number of the largest denomination.

Here's my take on this:
public IEnumerable<List<int>> GetDenominations(List<int> denominations, int value) =>
GetDenominations(new List<int>(), denominations, value);
private IEnumerable<List<int>> GetDenominations(List<int> bills, List<int> denominations, int value)
{
int sum = bills.Sum();
if (sum == value)
{
yield return bills;
}
else if (sum < value && denominations.Any())
{
for (int i = 0; i < denominations.Count; i++)
{
List<int> denominations2 = denominations.Skip(i).ToList();
List<int> bills2 = bills.Append(denominations2.First()).ToList();
foreach (var result in GetDenominations(bills2, denominations2, value))
{
yield return result;
}
}
}
}
That produces all valid combinations of the denominations that add up the value passed.
I get the results like this:
IEnumerable<List<int>> results = GetDenominations(new List<int>() { 10, 50, 100 }, 170);
And formatting is just a little LINQ work:
string output =
String
.Join(
Environment.NewLine,
results
.Reverse()
.Select(xs =>
String
.Join(
" + ",
xs
.OrderByDescending(x => x)
.GroupBy(x => x)
.Select(x => $"{x.Count()} x {x.Key}"))));
That gives me:
1 x 100 + 1 x 50 + 2 x 10
3 x 50 + 2 x 10
1 x 100 + 7 x 10
2 x 50 + 7 x 10
1 x 50 + 12 x 10
17 x 10

Related

C# median value among group calculation

I have to calculate the median for a group of values in one of my C# function. I have used the formula from the site, mathisfun. Following is my data model and the code.
public class DataModel
{
public string Group { get; set; }
public long? Population { get; set; }
}
Sample dataList is as follows,
> dataList Count = 7
> [0]: {DataModel}
> Group: "16 to 24" Population: 39657245
> [1]: {DataModel} Group: "25 to 34" Population: 58957845
> [2]: {DataModel} Group: "35 to 44" Population: 12557845
> [3]: {DataModel} Group: "45 to 54" Population: 25698746
> [4]: {DataModel} Group: "55 to 64" Population: 325487
Following is the function logic which takes the dataList as a input and returns the median value as output.
public int CalculateMedianAge(IList<DataModel> dataList)
{
int median = 0;
var sum = 0;
var sumRange = 0;
DataModel medianGroup = new DataModel();
foreach (var item in dataList)
{
sum = sum + (int)item.Population;
}
int range = (sum + 1) / 2;
foreach(var entry in dataList)
{
sumRange = sumRange + (int)entry.Population;
if (range > sumRange)
continue;
else
{
medianGroup = entry;
break;
}
}
var lowerBoundary = int.Parse(medianGroup.Group.Split(' ')[0]) - 0.5;
var cumulativeFrequency = 0;
for (int s = 0; s< dataList.IndexOf(medianGroup); s++)
{
cumulativeFrequency = cumulativeFrequency + (int)dataList[s].Population;
}
var width = int.Parse(medianGroup.Group.Split(' ')[2]) - int.Parse(medianGroup.Group.Split(' ')[0]);
//L is the lower class boundary of the group containing the median - lowerBoundary
//n is the total number of values - sum
//B is the cumulative frequency of the groups before the median group - cumulativeFrequency
//G is the frequency of the median group - (int)lowerBoundary.Population
//w is the group width - width
//MedianAge = L + (((n/2) - B) / G) * W
median = (int)(lowerBoundary + (((sum/2) - cumulativeFrequency) / (int)medianGroup.Population) * width);
return median;
}
It is working fine and I can able to get the median value as well. But I am trying to re-factor it with LINQ. I don't want to keep it with Continue and Break statements.
Can anyone suggest/re-factor the above?
This definitely looks bad:
var population = dataList.Sum(x => x.pop);
var aggregate = 0;
var median = dataList
.Select(x => new
{
split = x.Group.Split(" to "),
pop = (int)x.Population
})
.Select(x => new
{
from = int.Parse(x.split[0]),
to = int.Parse(x.split[1]),
x.pop
})
//median calculation here VVVV
.SelectMany(x=>
Enumerable
.Range(x.from, x.to - x.from + 1)
.Select(y=> new
{
age = y,
pop = x.pop/(x.to - x.from + 1) //tail lost here, for small values will return incorrect values. Distribution through linq is bad idea here.
})
)
.OrderBy(x => x.age)
.First(x => (aggregate+= x.pop) >= population/2)
.age;
PS: Not tested this. Your approach through for is good. Linq is bad to use here.

Mapping a multidimensional array

I have the following class
class Tile
{
public int height;
public int terrain;
}
And I have a 2D array of Tiles
Tile[,] area = new Tile[5,5];
How could I map my area from a Tile[,] to a int[,], where only the height is saved?
I tried doing this:
area.Select(tile => tile.height)
but apparently C# Multidimensional arrays do not implement IEnumerable.
How could I solve this problem?
How could I solve this problem?
By writing code. There's no "select" that works, so make your own:
static class Extensions
{
public static R[,] Select<T, R>(this T[,] items, Func<T, R> f)
{
int d0 = items.GetLength(0);
int d1 = items.GetLength(1);
R[,] result = new R[d0, d1];
for (int i0 = 0; i0 < d0; i0 += 1)
for (int i1 = 0; i1 < d1; i1 += 1)
result[i0, i1] = f(items[i0, i1]);
return result;
}
}
And now you have the extension method you want.
EXERCISES:
Which of the standard LINQ sequence operators make sense to adapt to multidimensional arrays, and which do not?
Are there operators you'd like to see on multidimensional arrays that are not standard LINQ operators but which you could implement as extension methods?
As there is no out of the box way to do this, you may try the workaround proposed here:
Extracted from the original post and all credit goes to original poster: Enumerating on Multi-dimentional arrays
public static class ArrayExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this Array target)
{
foreach (var item in target)
yield return (T)item;
}
}
If you really, reaaaallly, reaaaaaallly want, you could construct something like this:
public static void Main(string[] args)
{
var area = new Tile[5, 5];
for (var j = 0; j < 5; j++)
for (var i = 0; i < 5; i++)
area[i, j] = new Tile() { height = (j + 1) * (i + 1), terrain = 99 };
Your linq:
// this copies the data over from your area-array into a new int[5,5] array using
// IEnumerable.Aggregate(...) with an emtpy seeded int[5,5] array and
// leverages Enumerable.Range() with integer division + modular to get
// the indices right
var onlyHeights = Enumerable
.Range(0, 25)
.Aggregate(new int[5, 5], (acc, i) =>
{
acc[i / 5, i % 5] = area[i / 5, i % 5].height;
return acc;
});
Test:
for (var j = 0; j < 5; j++)
for (var i = 0; i < 5; i++)
Console.WriteLine($"area.height {area[i, j].height} => {onlyHeights[i, j]}");
Console.ReadLine();
}
Output:
area.height 1 => 1
area.height 2 => 2
area.height 3 => 3
area.height 4 => 4
area.height 5 => 5
area.height 2 => 2
area.height 4 => 4
area.height 6 => 6
area.height 8 => 8
area.height 10 => 10
area.height 3 => 3
area.height 6 => 6
area.height 9 => 9
area.height 12 => 12
area.height 15 => 15
area.height 4 => 4
area.height 8 => 8
area.height 12 => 12
area.height 16 => 16
area.height 20 => 20
area.height 5 => 5
area.height 10 => 10
area.height 15 => 15
area.height 20 => 20
area.height 25 => 25
But thats just some nested for's in disguise.
And if you want a more generic LINQ-like method accepting higher dimensional arrays.
public static class ArrayExtensions
{
private static IEnumerable<int[]> CreatePermutations(int[] lengths, int pos = 0)
{
for (var i = 0; i < lengths[pos]; i++)
{
var newArray = (int[])lengths.Clone();
newArray[pos] = i;
if (pos + 1 >= lengths.Length)
{
yield return newArray;
continue;
}
foreach (var next in CreatePermutations(newArray, pos + 1)) yield return next;
}
}
public static Array Select<T,P>(this Array target, Func<T, P> func)
{
var dimensions = target.Rank;
var lengths = Enumerable.Range(0, dimensions).Select(d => target.GetLength(d)).ToArray();
var array = Array.CreateInstance(typeof(P), lengths);
var permutations = CreatePermutations(lengths);
foreach (var index in permutations)
{
array.SetValue(func((T)target.GetValue(index)), index);
}
return array;
}
}
Which you can call like.
var heightOnly = area.Select<Tile, int>(a => a.height);

Split a List into several Lists based on criteria using LINQ

I have a list of integers, which I would like to split into 2 or more lists based upon meeting a certain criteria. For example:
List<int> myList = new List<int>();
myList.Add(100);
myList.Add(200);
myList.Add(300);
myList.Add(400);
myList.Add(200);
myList.Add(500);
I would like to split the list into several lists, each of which contains all items which total <= 600. In the above, it would then result in 3 separate List objects.
List 1 would contain 100, 200 300
List 2 would contain 400, 200
List 3 would contain 500
Ideally, I'd like it to be a single LINQ statement.
Although doable, this is an excellent example of what LINQ is not for. Check yourself.
Having
var myList = new List<int> { 100, 200, 300, 400, 200, 500, };
int maxSum = 600;
"Pure" LINQ (the power of Aggregate)
var result = myList.Aggregate(
new { Sum = 0, List = new List<List<int>>() },
(data, value) =>
{
int sum = data.Sum + value;
if (data.List.Count > 0 && sum <= maxSum)
data.List[data.List.Count - 1].Add(value);
else
data.List.Add(new List<int> { (sum = value) });
return new { Sum = sum, List = data.List };
},
data => data.List)
.ToList();
A normal (non LINQ) implementation of the above
var result = new List<List<int>>();
int sum = 0;
foreach (var value in myList)
{
if (result.Count > 0 && (sum += value) <= maxSum)
result[result.Count - 1].Add(value);
else
result.Add(new List<int> { (sum = value) });
}
For completeness (and some fun), a "Hackish" LINQ (the power of closures and C# operators)
int sum = 0, key = -1;
var result = myList.GroupBy(x => key >= 0 && (sum += x) <= maxSum ? key : ++key + (sum = x) * 0, (k, e) => e.ToList()).ToList();
Here is the solution to your problem. I am not sure if that is the best case solver but it will surely do the job:
List<int> First = myList.Where(x => x <= 300).ToList();
List<int> Second = myList.Where(x => x == 400 || x == 200).ToList();
List<int> Third = myList.Where(x => x == 500).ToList();
It does query through the list and checks for values that meets the requirements then it will convert IEnumerable into the List.
This will do what you want for a list any size but maybe not as short as you are looking for. You would have to write a LINQ extension method to shorten it but then it become a bit more complicated.
List<int> myList = new List<int>();
myList.Add(100);
myList.Add(200);
myList.Add(300);
myList.Add(400);
myList.Add(200);
myList.Add(500);
var result = new List<List<int>>();
var skip = 0;
while (skip < myList.Count)
{
var sum = 0;
result.Add(myList.Skip(skip).TakeWhile(x =>
{
sum += x;
return sum <= 600;
}).ToList());
skip += result.Last().Count();
}

Is there something like `continue` to bypass or skip an iteration of query in LINQ?

Take this example:
int[] queryValues1 = new int[10] {0,1,2,3,4,5,6,7,8,9};
int[] queryValues2 = new int[100]; // this is 0 to 100
for (int i = 0; i < queryValues2.Length; i++)
{
queryValues2[i] = i;
}
var queryResult =
from qRes1 in queryValues1
from qRes2 in queryValues2
where qRes1 * qRes2 == 12
select new { qRes1, qRes2 };
foreach (var result in queryResult)
{
textBox1.Text += result.qRes1 + " * " + result.qRes2 + " = 12" + Environment.NewLine;
}
Obviously this code will result in:
1 * 12 = 12
2 * 6 = 12
3 * 4 = 12
4 * 3 = 12
6 * 2 = 12
But what I need is only the first 3 lines. That is I do not want if 2*6 = 12 the query checks if 6*2 is also 12. Is there a way to filter this in the LINQ query or I have to do it in the foreach loop afterward?
My question just is a sample to show what I mean. so I want to know the way of doing such thing no matter what is the type of object being linqed to!
In general the simple solution would be more where conditions since the where clauses are what by definition cause LINQ to skip iterations:
var queryResult =
from qRes1 in queryValues1
from qRes2 in queryValues1
where qRes1 * qRes2 == 12
&& qRes1 <= Math.Sqrt(12)
select new { qRes1, qRes2 };
You could use .Distinct() and create your own IEqualityComparer that compares objects based on what 'equals' means in your case.
So, for your original example:
class PairSetEqualityComparer : IEqualityComparer<Tuple<int, int>>
{
public bool Equals(Tuple<int, int> x, Tuple<int, int> y)
{
return (x.Item1 == y.Item1 && x.Item2 == y.Item2) ||
(x.Item1 == y.Item2 && x.Item2 == y.Item1);
}
public int GetHashCode(Tuple<int, int> obj)
{
return obj.Item1*obj.Item2;
}
}
And, you use it like this:
var queryResult =
(from qRes1 in queryValues1
from qRes2 in queryValues2
where qRes1 * qRes2 == 12
select new Tuple<int, int>(qRes1, qRes2)).Distinct(new PairSetEqualityComparer());
TakeWhile(condition):Returns elements from a sequence as long as a specified condition is true, and then skips the remaining elements.
foreach (var result in queryResult.TakeWhile(x => x.qRes1 <= Math.Sqrt(12)))

Finding if a target number is the sum of two numbers in an array via LINQ

A basic solution would look like this:
bool sortTest(int[] numbers, int target)
{
Array.Sort(numbers);
for(int i = 0; i < numbers.Length; i++)
{
for(int j = numbers.Length-1; j > i; j--)
{
if(numbers[i] + numbers[j] == target)
return true;
}
}
return false;
}
Now I'm very new to LINQ but this is what I have written so far:
var result = from num in numbers
where numbers.Contains(target -num)
select num;
if (result.Count() > 0)
return true;
return false;
Now i'm running into an issue given the following example:
Array: 1, 2, 4, 5, 8
Target: 16
It should return back false, but it's catching 16-8=8. So how do I go about not letting it notice itself in the contains check? Or can I make a second array each time within the query that doesn't contain the number I'm working with(thus solving the problem)?
Thanks in advance.
Is this what you're looking for?
var result = from n1 in numbers
from n2 in numbers
where n1 != n2 && n1 + n2 == target
select new { n1, n2 };
[Edit]
This returns matches twice and ignores the situation where a number is duplicated in the array. You can't handle these situations using Expression Syntax because you can't access the index of a matched item, but you can do it like this:
var result = numbers.Select((n1, idx) =>
new {n1, n2 = numbers.Take(idx).FirstOrDefault(
n2 => n1 + n2 == target)}).Where(pair => pair.n2 != 0);
As long as you don't have any zeros in your array.
[Further thought Edit]
The perfect mix solution:
var result = from item in numbers.Select((n1, idx) =>
new {n1, shortList = numbers.Take(idx)})
from n2 in item.shortList
where item.n1 + n2 == target
select new {n1 = item.n1, n2};
What I'd do to solve this problem in general is first write a "chooser".
public static IEnumerable<IEnumerable<T>> Chooser<T>(this IList<T> sequence, int num)
{ ... left as an exercise ... }
The output of the chooser is a sequence of sequences. Each sub-sequence is of length num, and consists of elements chosen from the original sequence. So if you passed { 10, 30, 20, 50 } as the sequence and 3 for num, you'd get the sequence of sequences:
{10, 30, 20}, {10, 30, 50}, {10, 20, 50}, {30, 20, 50}
as a result.
Once you've written Chooser, the problem becomes easy:
var results =
from subsequence in numbers.Chooser(2)
where subsequence.Sum() == target
select subsequence;
And now you can solve the problem for subsequences of other sizes, not just pairs.
Writing Chooser is a bit tricky but it's not too hard.
To improve on pdr's reply and address the concerns mentioned in the comments you could use the overloaded Select method to compare the indices of the items and ensure uniqueness.
public bool sortTest(int[] numbers, int target)
{
var indexedInput = numbers.Select((n, i) => new { Number = n, Index = i });
var result = from x in indexedInput
from y in indexedInput
where x.Index != y.Index
select x.Number + y.Number == target;
return result.Any(item => item);
}
Or in dot notation:
var result = numbers.Select((n, i) => new { Number = n, Index = i })
.SelectMany(
x => indexedInput,
(x, y) => new { x = x, y = y })
.Where(item => item.x.Index != item.y.Index)
.Select(item => item.x.Number + item.y.Number == target);

Categories

Resources