Handling temporary calculation in Linq - c#

When solving an interview question
Question
A six digit number need to be found in such a manner when it is multiplied by an integer between 2 and 9 gives the original six digit number when its digits are reversed.
Example:
Suppose I multiply 219978 * 4 i get 879912 ,when reverse 879912 I will get 219978 back.
I solved it using
for (long l = 100000; l < 999999; l++)
{
var num = l.ToString();
for (int i = 3; i < 9; i++)
{
var mul = l * i;
string str = mul.ToString();
char[] splitDigits = str.ToCharArray();
string reversedDigit =
new string(splitDigits.Reverse().ToArray());
if (reversedDigit.CompareTo(num) == 0)
{
Console.WriteLine("{0} * {1}= {2},
when multiplied {3} ", num, i, mul,reversedDigit);
}
}
}
The original task was to solve it using linq. I have bit confusion in handling temp calculations for example
when i use
var = from l in Enumerable.Range(100000,999999)
from i in Enumerable.Range(3,9)
What is the way to handle temporary calculations like var num = l.ToString(),etc in linq.It confused me a lot to finish it in Linq.Help is appreciated.

You want let...
// NOTE: buggy; see below
var qry = from l in Enumerable.Range(100000, 999999)
from i in Enumerable.Range(3, 9)
let s = l.ToString()
let t = (l * i).ToString()
where s.Reverse().SequenceEqual(t)
select new { l, i };
var a = qry.First();
Console.WriteLine("an answer...");
Console.WriteLine("{0} x {1} = {2}", a.l, a.i, a.l * a.i);
Console.WriteLine("all answers...");
foreach (var row in qry)
{
Console.WriteLine("{0} x {1} = {2}", row.l, row.i, row.l * row.i);
}
with first answer (note the inclusion of 9 is taken from your original version of the code, but it may be desirable to use Range(3,8) instead):
109989 x 9 = 989901
Optimised version (and correct range):
var qry = from l in Enumerable.Range(100000, 999999 - 100000)
let s = l.ToString()
let sReversed = new string(s.Reverse().ToArray())
let wanted = int.Parse(sReversed)
from i in Enumerable.Range(3, 8 - 3)
where l * i == wanted
select new { l, i };
This reduces the number of strings created, uses integer equality, and correctly uses the range (the second parameter to Range is the count, not the end).

Here's another solution that matches the problem statement with a few helper methods for clarity (which could be moved into the original linq query):
private static IEnumerable<int> SixDigitNumbers = Enumerable.Range(100000, (999999 - 100000));
private static IEnumerable<int> Multipliers = Enumerable.Range(2, 8);
static void Main(string[] args)
{
var Solutions = from OriginalNumber in SixDigitNumbers
from Multiplier in Multipliers
let MultipliedNumber = (OriginalNumber * Multiplier)
where MultipliedNumber < 999999 && ResultIsNumericPalindrome(OriginalNumber, Multiplier)
select new { MultipliedNumber, OriginalNumber, Multiplier };
var AllSolutions = Solutions.ToList();
}
private static string Reverse(string Source)
{
return new String(Source.Reverse().ToArray());
}
private static bool ResultIsNumericPalindrome(int Original, int Multiplier)
{
return (Original.ToString() == Reverse((Original * Multiplier).ToString()));
}
Here are ALL of the solutions:
{ MultipliedNumber = 989901, OriginalNumber = 109989, Multiplier = 9 }
{ MultipliedNumber = 879912, OriginalNumber = 219978, Multiplier = 4 }
Be careful with Enumerable.Range - I see one person responding to this question made the mistake of excluding two numbers requested in the problem statement.

Related

For a given word calculate the number of possible anagrams

For a given word calculate the number of possible anagrams.
The resulting words do not have to exist in the dictionary.
Anagrams do not have to be repeated and anagrams do not have to be generated, only their number calculated.
The last test is not working and I do not know how should I make it work. Can you help me, please?
Here is my code:
using System;
static void Main(string[] args)
{
string word = Console.ReadLine();
int wordLenth = word.Length;
int sameLetter = 1;
for (int i=0;i<wordLenth;i++)
{
for (int j=i+1;j<wordLenth;j++)
{
if (word[i]==word[j])
{
sameLetter++;
}
}
}
int firstResult=1, secondResult=1, lastResult;
for (int i=1; i <= wordLenth; i++)
{
firstResult *= i;
}
for (int i = 1; i <= sameLetter; i++)
{
secondResult *= i;
}
lastResult = firstResult / secondResult;
Console.WriteLine(lastResult);
}
Results:
Compilation successfully executed.
Test 1: Correctly calculate the number of anagrams for "abc" - successful
Test 2: Correctly calculate the number of anagrams for "abc" - success
Test 3: Correctly calculates the number of anagrams for "aaab" - failed
Expected results: "4"
Results obtained: "1"
The submitted solution does not correctly calculate the number of unique anagrams if there are repeating letters.
If you have word of length n with m distinct letters w1, ..., wm where wi is occurence of ith letter,
the number of possible anagrams is
Math:
N = n! / w1! / w2! / ... / wm!
For instance:
For abc we have n = 3, m = 3, w1 = w2 = w3 = 1:
N = 3! / 1! / 1! / 1! = 6 / 1 / 1 / 1 = 6
For aaab we have n = 4, m = 2, w1 = 3, w2 = 1:
N = 4! / 3! / 1! = 24 / 6 / 1 = 4
Code:
using System.Linq;
using System.Numerics;
...
private static BigInteger Factorial(int value) {
BigInteger result = 1;
for (int i = 2; i <= value; ++i)
result *= i;
return result;
}
private static BigInteger CountAnagrams(string value) {
if (string.IsNullOrEmpty(value))
return 1;
return value
.GroupBy(c => c)
.Aggregate(Factorial(value.Length), (s, group) => s / Factorial(group.Count()));
}
Demo: (Fiddle)
string[] tests = new string[] {
"a",
"aaa",
"abc",
"aaab",
"abracadabra",
"stackoverflow",
};
string report = string.Join(Environment.NewLine, tests
.Select(test => $"{test,20} => {CountAnagrams(test)}"));
Console.Write(report);
Outcome:
a => 1
aaa => 1
abc => 6
aaab => 4
abracadabra => 83160
stackoverflow => 3113510400
Edit: If you are not allowed to use System.Numerics and System.Linq you can try using long:
private static long Factorial(int value)
{
long result = 1;
for (int i = 2; i <= value; ++i)
result *= i;
return result;
}
private static long CountAnagrams(string value)
{
if (string.IsNullOrEmpty(value))
return 1L;
Dictionary<char, int> groups = new Dictionary<char, int>();
foreach (var c in value)
if (groups.TryGetValue(c, out int v))
groups[c] += 1;
else
groups.Add(c, 1);
long result = Factorial(value.Length);
foreach (int v in groups.Values)
result /= Factorial(v);
return result;
}

how to optimize FirstOrDefault Statement in linq

I have a two linq statements that the first one takes 25 ms and the second one takes 1100 ms second in a loop of 100,000.
I have replaced FirstAll with ElementAt and even used foreach to get the first element, but still takes the same time.
Is there any faster way to get the first element ?
I have considered few other questions but still couldn't find any solution to solve this problem.
var matches = (from subset in MyExtensions.SubSetsOf(List1)
where subset.Sum() <= target
select subset).OrderByDescending(i => i.Sum());
var match = matches.FirstOrDefault(0);
Also tried:
foreach (var match in matches)
{
break;
}
Or even:
var match = matches.ElementAt(0);
Any comments would be appreciated.
EDIT: here is the code for SubSetOf
public static class MyExtensions
{
public static IEnumerable<IEnumerable<T>> SubSetsOf<T>(this IEnumerable<T> source)
{
// Deal with the case of an empty source (simply return an enumerable containing a single, empty enumerable)
if (!source.Any())
return Enumerable.Repeat(Enumerable.Empty<T>(), 1);
// Grab the first element off of the list
var element = source.Take(1);
// Recurse, to get all subsets of the source, ignoring the first item
var haveNots = SubSetsOf(source.Skip(1));
// Get all those subsets and add the element we removed to them
var haves = haveNots.Select(set => element.Concat(set));
// Finally combine the subsets that didn't include the first item, with those that did.
return haves.Concat(haveNots);
}
}
You call Sum twice - it's bad. Precalc it:
var matches = MyExtensions.SubSetsOf(List1)
.Select(subset => new { subset, Sum = subset.Sum() })
.Where(o => o.Sum < target).OrderByDescending(i => i.Sum);
var match = matches.FirstOrDefault();
var subset = match != null ? match.subset : null;
As Jason said, it's a subset sum problem - the option of Knapsack Problem where weight is equal to value. The simplest solution - generate all subsets and check thiers sum, but this algorithm has horrible complexity. So, our optimization does not matter.
You shoul use dynamic programmig to solve this problem:
Let assume a two-dimensional array D(i, c) - maximal sum of i elements that is less or equal to c. N - is amount of elements (list size). W - max sum (your target).
D(0,c) = 0 for every c, because you have no elements :)
And changing c from 1 to W and i from 1 to N let's compute
D(i,c) = max(D(i-1,c),D(i-1,c-list[i])+list[i]).
To restore subset, we must store array of parents and set them during calculations.
Another examples are here.
Whole code:
class Program
{
static void Main(string[] args)
{
var list = new[] { 11, 2, 4, 6 };
var target = 13;
var n = list.Length;
var result = KnapSack(target, list, n);
foreach (var item in result)
{
Console.Write(item + " ");
}
}
private static List<int> KnapSack(int target, int[] val, int n)
{
var d = new int[n + 1, target + 1];
var p = new int[n + 1, target + 1];
for (var i = 0; i <= n; i++)
{
for (var c = 0; c <= target; c++)
{
p[i, c] = -1;
}
}
for (int i = 0; i <= n; i++)
{
for (int c = 0; c <= target; c++)
{
if (i == 0 || c == 0)
{
d[i, c] = 0;
}
else
{
var a = d[i - 1, c];
if (val[i - 1] <= c)
{
var b = val[i - 1] + d[i - 1, c - val[i - 1]];
if (a > b)
{
d[i, c] = a;
p[i, c] = p[i - 1, c];
}
else
{
d[i, c] = b;
p[i, c] = i - 1;
}
}
else
{
d[i, c] = a;
p[i, c] = p[i - 1, c];
}
}
}
}
//sum
//Console.WriteLine(d[n, target);
//restore set
var resultSet = new List<int>();
var m = n;
var s = d[n, target];
var t = p[m, s];
while (t != -1)
{
var item = val[t];
resultSet.Add(item);
m--;
s -= item;
t = p[m, s];
}
return resultSet;
}
}
It looks like the general problem you are trying solve is to find the subset of numbers with the largest sum less than target. The execution time of your linq function is a symptom of your solution. That is a well known and much researched problem called the 'knapsack problem'. I believe your specific variant would fall into the 'bounded knapsack problem' class with the weight being equal to the value. I would start by researching that. The solution you have implemented, brute forcing every possible subset, is known as the 'naive' solution. I am pretty sure it is the worst performing of all possible solutions.

Multiplication Combinations (Simple C#)

So I have a list of ulong prime numbers, with variable lengths.
Ex: 2,5,7,3
And I want to create every multiplying combination, excluding ALL the numbers multiplied together.
(2*5*7*3 in this case).
Ex: 2,3,5,6,7,10,14,15,21,30,35,42,70,105.
I have tried a couple solutions using the "foreach" loop, but I just can't seem to get it. It seems too easy. What might be an efficient way to going about this?
My main issue that I run into is that when I add a new value to the list, the "foreach" loop causes an error because I changed it. I can't think of a way around that other than do a whole bunch of new lists. It seems to me like there should be a really simple, clean solution that I am just overcomplicating.
I tried the "Build-up" approaching, multiplying the base factors together, to create larger ones and so on, and the "Build-down" approaching, starting with the large number, and then factoring it (shown in my example). This is what I tried:
List<ulong> c, f;
ulong i;
//Some code then sets c to the factors (2, 3, 5, and 7)
//i is then set to the c set multiplied together (2*3*5*7)
//if the c is a factor, divide and add it to the new list f (the final list)
foreach (ulong u in c)
{
if (i % u == 0)
{
f.Add(i/u);
Console.WriteLine(i / u);
}
}
// Keep on dividing the numbers down, until you get the original factors added to the list
for (int j = 0; j < f.Count -1; j++)
{
foreach (ulong u in c)
{
foreach (ulong v in f)
{
if (v % u == 0)
{
if (v / u != 1 && !f.Contains(v / u))
{
f.Add(v / u);
}
}
}
}
}
Expected Output with input (2 5 7 3):
2
5
3
7
2 * 3 = 6
2 * 5 = 10
2 * 7 = 14
5 * 7 = 35
5 * 3 = 15
7 * 3 = 21
2 * 5 * 7 = 70
2 * 5 * 3 = 30
2 * 3 * 7 = 42
5 * 7 * 3 = 105
This works to get the numbers you want:
Func<IEnumerable<ulong>, IEnumerable<ulong>> f = null;
f = xs =>
{
if (xs.Any())
{
return f(xs.Skip(1))
.SelectMany(x =>
new [] { xs.First() * x, x });
}
else
{
return new ulong[] { 1 };
}
};
You use it like this:
var primes = new ulong[] { 2, 5, 7, 3 };
var results = f(primes)
.OrderBy(x => x)
.ToArray();
results = results
.Skip(1)
.Take(results.Length - 2)
.ToArray();
I had to do the Skip/Take to get rid of the two cases you wanted to avoid.
The result I get is:
If you'd like it as an (almost) one-liner here it is:
Func<IEnumerable<ulong>, IEnumerable<ulong>> f = null;
f = xs => xs.Any() ? f(xs.Skip(1)).SelectMany(x => new [] { xs.First() * x, x }) : new ulong[] { 1 };
The following code should give you exactly what you need with any number of items in your list
class Program
{
static void Main(string[] args)
{
MultiplyFactors(new List<ulong>() { 2, 3, 5, 7 });
Console.ReadLine();
}
public static void MultiplyFactors(List<ulong> numbers)
{
var factorCombinations = CreateSubsets(numbers.ToArray());
foreach (var factors in factorCombinations)
{
// set initial result to identity value. (any number multiplied by itself is 1)
ulong result = 1;
// multiply all factors in combination together
for (int i = 0; i < factors.Count(); i++)
{
result *= factors[i];
}
// Output for Display
Console.WriteLine(String.Format("{0}={1}", String.Join("x", factors), result));
}
}
private static List<T[]> CreateSubsets<T>(T[] originalArray)
{
// From http://stackoverflow.com/questions/3319586/getting-all-possible-permutations-from-a-list-of-numbers
var subsets = new List<T[]>();
for (int i = 0; i < originalArray.Length; i++)
{
int subsetCount = subsets.Count;
subsets.Add(new T[] {originalArray[i]});
for (int j = 0; j < subsetCount; j++)
{
T[] newSubset = new T[subsets[j].Length + 1];
subsets[j].CopyTo(newSubset, 0);
newSubset[newSubset.Length - 1] = originalArray[i];
subsets.Add(newSubset);
}
}
return subsets;
}
}
This will give you the following results for your inputs of 2,3,5,7.
2=2
3=3
2x3=6
5=5
2x5=10
3x5=15
2x3x5=30
7=7
2x7=14
3x7=21
2x3x7=42
5x7=35
2x5x7=70
3x5x7=105
2x3x5x7=210
This could have been through recursion but this method was probably just as simple. The trick is creating your list of subsets. Once you have that, you simply multiply all of the elements of each subset together.

How can I find out which numbers in a defined set add up to another number? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have a number 6 and now I need to search inside an array of ints if any of the numbers can be added together to get 6.
Example:
1,2,3,5,4
In the above array I can take 1+2+3 which makes 6.
I can also take 4+2 which is 6.
The question is how do I find those individual numbers that can sum up to the number 6.
One possible option is to get a list of all combinations of items in the array, then check which one of those has the sum of your target number.
I found an extension method for getting the combinations here (copied below).
public static IEnumerable<T[]> Combinations<T>(this IList<T> argList, int argSetSize)
{
if (argList == null) throw new ArgumentNullException("argList");
if (argSetSize <= 0) throw new ArgumentException("argSetSize Must be greater than 0", "argSetSize");
return combinationsImpl(argList, 0, argSetSize - 1);
}
private static IEnumerable<T[]> combinationsImpl<T>(IList<T> argList, int argStart, int argIteration, List<int> argIndicies = null)
{
argIndicies = argIndicies ?? new List<int>();
for (int i = argStart; i < argList.Count; i++)
{
argIndicies.Add(i);
if (argIteration > 0)
{
foreach (var array in combinationsImpl(argList, i + 1, argIteration - 1, argIndicies))
{
yield return array;
}
}
else
{
var array = new T[argIndicies.Count];
for (int j = 0; j < argIndicies.Count; j++)
{
array[j] = argList[argIndicies[j]];
}
yield return array;
}
argIndicies.RemoveAt(argIndicies.Count - 1);
}
}
Now you just need to call it with the number of combinations you want in your groups. For example, if you wanted to find groups of 2:
List<int> ints = new List<int>() { 1, 2, 3, 4, 5 };
int target = 6;
var combs2 = ints.Combinations(2)
.Where(x => x.Sum() == target);
This will return 1,5 and 2,4. You can then repeat this up to the maximum number of items you want in a group.
If you want to get all the results at once, make a new extension method that will do the unioning for you:
public static IEnumerable<T[]> AllCombinations<T>(this IList<T> argsList)
{
for (int i = 1; i <= argsList.Count; i++)
{
foreach (var combo in argsList.Combinations(i))
{
yield return combo;
}
}
}
Then you can get all your combinations at once by running
var allCombos = ints.AllCombinations()
.Where(x => x.Sum() == target);
So for your example, it will return 1,5, 2,4, and 1,2,3 in one collection.
If you want to know whether (and discover these numbers) two numbers sum to X it's an easy task and you can do it O(n) on average.
HashSet<int> numbers = new HashSet<int>(yourNumberArray);
foreach(int number in numbers)
if(numbers.Contains(x-number))
Console.WriteLine(number + " " + "numbers[x-number]");
However when you want to know if x1,x2,...,xk numbers sum to X it's NP-complete problem and no polynominal bounded solution is known (also it is not known does such solution exists). If number of items in your set is small (about ~20-30) you can brute-force your result by enumerating all subsets.
for (int i=1; i< (1 << setSize); ++i)
{
check does number in current set sum to X by bitwise operations on i
(treat number binary representation as information about set
(binary one means item is in set, zero means item is not in set)
}
You can also reduce this problem to knapsack problem and get pseudo-polynominal time, however maximum value in set shouldn't be big. For more information check: http://www.geeksforgeeks.org/dynamic-programming-subset-sum-problem/
You can find all combinations which results 6 using Lipski's algorithm like this:
static List<List<int>> FindCombinations(int x)
{
var combinations = new List<List<int>>();
var P = new int[10];
var R = new int[10];
combinations.Add(Enumerable.Repeat(1,x)); // first combination
P[1] = x;
R[1] = 1;
int d = 1, b, sum;
while (P[1] > 1)
{
sum = 0;
if (P[d] == 1)
{
sum = sum + R[d];
d = d - 1;
}
sum = sum + P[d];
R[d] = R[d] - 1;
b = P[d] - 1;
if (R[d] > 0) d++;
P[d] = b;
R[d] = sum/b;
b = sum%b;
if (b != 0)
{
d++;
P[d] = b;
R[d] = 1;
}
List<int> temp = new List<int>();
for (int i = 1; i <= d; i++)
temp = temp.Concat(Enumerable.Repeat(P[i], R[i])).ToList();
combinations.Add(temp);
}
return combinations;
}
Then all you need to is compare each sequence with your numbers:
var combinations = FindCombinations(6);
var numbers = new List<int> {1, 2, 3, 5, 4,6};
var result =
combinations.Where(x => x.Intersect(numbers).Count() == x.Count)
.Select(x => x.Intersect(numbers))
.ToList();
Here is the result in LINQPad:

How to get all the possible 3 letter permutations? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Listing all permutations of a string/integer
For example,
aaa .. aaz .. aba .. abz .. aca .. acz .. azz .. baa .. baz .. bba .. bbz .. zzz
Basically, imagine counting binary but instead of going from 0 to 1, it goes from a to z.
I have been trying to get this working to no avail and the formula is getting quite complex. I'm not sure if there's a simpler way to do it.
Edit
I have something like this at the moment but it's not quite there and I'm not sure if there is a better way:
private IEnumerable<string> GetWordsOfLength(int length)
{
char letterA = 'a', letterZ = 'z';
StringBuilder currentLetters = new StringBuilder(new string(letterA, length));
StringBuilder endingLetters = new StringBuilder(new string(letterZ, length));
int currentIndex = length - 1;
while (currentLetters.ToString() != endingLetters.ToString())
{
yield return currentLetters.ToString();
for (int i = length - 1; i > 0; i--)
{
if (currentLetters[i] == letterZ)
{
for (int j = i; j < length; j++)
{
currentLetters[j] = letterA;
}
if (currentLetters[i - 1] != letterZ)
{
currentLetters[i - 1]++;
}
}
else
{
currentLetters[i]++;
break;
}
}
}
}
For a variable amount of letter combinations, you can do the following:
var alphabet = "abcdefghijklmnopqrstuvwxyz";
var q = alphabet.Select(x => x.ToString());
int size = 4;
for (int i = 0; i < size - 1; i++)
q = q.SelectMany(x => alphabet, (x, y) => x + y);
foreach (var item in q)
Console.WriteLine(item);
var alphabet = "abcdefghijklmnopqrstuvwxyz";
//or var alphabet = Enumerable.Range('a', 'z' - 'a' + 1).Select(i => (char)i);
var query = from a in alphabet
from b in alphabet
from c in alphabet
select "" + a + b + c;
foreach (var item in query)
{
Console.WriteLine(item);
}
__EDIT__
For a general solution, you can use the CartesianProduct here
int N = 4;
var result = Enumerable.Range(0, N).Select(_ => alphabet).CartesianProduct();
foreach (var item in result)
{
Console.WriteLine(String.Join("",item));
}
// Eric Lippert’s Blog
// Computing a Cartesian Product with LINQ
// http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
// base case:
IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
foreach (var sequence in sequences)
{
var s = sequence; // don't close over the loop variable
// recursive case: use SelectMany to build the new product out of the old one
result =
from seq in result
from item in s
select seq.Concat(new[] { item });
}
return result;
}
You have 26^3 counts for 3 "digits". Just iterate from 'a' to 'z' in three loops.
Here's a very simple solution:
for(char first = 'a'; first <= (int)'z'; first++)
for(char second = 'a'; second <= (int)'z'; second++)
for(char third = 'a'; third <= (int)'z'; third++)
Console.WriteLine(first.ToString() + second + third);

Categories

Resources