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.
Related
I am having trouble with a small bit of code, which in a random size array, with random number pairs, except one which has no pair.
I need to find that number which has no pair.
arLength is the length of the array.
but i am having trouble actually matching the pairs, and finding the one which has no pair..
for (int i = 0; i <= arLength; i++)
{ // go through the array one by one..
var number = nArray[i];
// now search through the array for a match.
for (int e = 0; e <= arLength; e++)
{
if (e != i)
{
}
}
}
I have also tried this :
var findValue = nArray.Distinct();
I have searched around, but so far, i haven't been able to find a method for this.
This code is what generates the array, but this question isn't about this part of the code, only for clarity.
Random num = new Random();
int check = CheckIfOdd(num.Next(1, 1000000));
int counter = 1;
while (check <= 0)
{
if (check % 2 == 0)
{
check = CheckIfOdd(num.Next(1, 1000000)); ;
}
counter++;
}
int[] nArray = new int[check];
int arLength = 0;
//generate arrays with pairs of numbers, and one number which does not pair.
for (int i = 0; i < check; i++)
{
arLength = nArray.Length;
if (arLength == i + 1)
{
nArray[i] = i + 1;
}
else
{
nArray[i] = i;
nArray[i + 1] = i;
}
i++;
}
You can do it using the bitwise operator ^, and the complexity is O(n).
Theory
operator ^ aka xor has the following table:
So suppose you have only one number without pair, all the pairs will get simplified because they are the same.
var element = nArray[0];
for(int i = 1; i < arLength; i++)
{
element = element ^ nArray[i];
}
at the end, the variable element will be that number without pair.
Distict will give you back the array with distinct values. it will not find the value you need.
You can GroupBy and choose the values with Count modulo 2 equals 1.
var noPairs = nArray.GroupBy(i => i)
.Where(g => g.Count() % 2 == 1)
.Select(g=> g.Key);
You can use a dictionary to store the number of occurrences of each value in the array. To find the value without pairs, look for a (single) number of occurrences smaller than 2.
using System.Linq;
int[] data = new[] {1, 2, 3, 4, 5, 3, 2, 4, 1};
// key is the number, value is its count
var numberCounts = new Dictionary<int, int>();
foreach (var number in data) {
if (numberCounts.ContainsKey(number)) {
numberCounts[number]++;
}
else {
numberCounts.Add(number, 1);
}
}
var noPair = numberCounts.Single(kvp => kvp.Value < 2);
Console.WriteLine(noPair.Key);
Time complexity is O(n) because you traverse the array only a single time and then traverse the dictionary a single time. The same dictionary can also be used to find triplets etc.
.NET Fiddle
An easy and fast way to do this is with a Frequency Table. Keep a dictionary with as key your number and as value the number of times you found it. This way you only have to run through your array once.
Your example should work too with some changes. It will be a lot slower if you have a big array.
for (int i = 0; i <= arLength; i++)
{
bool hasMatch = false;
for (int e = 0; e <= arLength; e++)
{
if (nArray[e] == nArray[i])//Compare the element, not the index.
{
hasMatch = true;
}
}
//if hasMatch == false, you found your item.
}
All you have to do is to Xor all the numbers:
int result = nArray.Aggregate((s, a) => s ^ a);
all items which has pair will cancel out: a ^ a == 0 and you'll have the distinc item: 0 ^ 0 ^ ...^ 0 ^ distinct ^ 0 ^ ... ^0 == distinct
Because you mentioned you like short and simple in a comment, how about getting rid of most of your other code as well?
var total = new Random().Next(500000) * 2 + 1;
var myArray = new int[total];
for (var i = 1; i < total; i+=2)
{
myArray[i] = i;
myArray[i -1] = i;
}
myArray[total - 1] = total;
Then indeed use Linq to get what you are looking for. Here is a slight variation, returning the key of the item in your array:
var key = myArray.GroupBy(t => t).FirstOrDefault(g=>g.Count()==1)?.Key;
public static int n;
public static int w;
public static int[] s;
public static int[] p;
static void Main(string[] args)
{
n = 5;
w = 5;
s = new int[n + 1];
p = new int[n + 1];
Random rnd = new Random();
for (int i = 1; i <= n; i++)
{
s[i] = rnd.Next(1, 10);
p[i] = rnd.Next(1, 10);
}
Console.WriteLine(F_recursion(n, w));
Console.WriteLine(DP(n, w));
}
// recursive approach
public static int F_recursion(int n, int w)
{
if (n == 0 || w == 0)
return 0;
else if (s[n] > w)
return F_recursion(n - 1, w);
else
{
return Math.Max(F_recursion(n - 1, w), (p[n] + F_recursion(n - 1, w - s[n])));
}
}
// iterative approach
public static int DP(int n, int w)
{
int result = 0;
for (int i = 1; i <= n; i++)
{
if (s[i] > w)
{
continue;
}
else
{
result += p[i];
w = w - s[i];
}
}
return result;
}
I need to convert F_recursion function to iterative. I currently written following function DP that sometimes works but not always. I learned that problem is in F_recursion(n - 1, w - s[n]) I have no idea how to make w - s[n] work correctly in iterative solution. If change w - s[n] and w - s[i] to only w then program always work.
In Console:
s[i] = 2 p[i] = 3
-------
s[i] = 3 p[i] = 4
-------
s[i] = 5 p[i] = 3
-------
s[i] = 3 p[i] = 8
-------
s[i] = 6 p[i] = 6
-------
Recursive:11
Iteration:7
but sometimes it works
s[i] = 5 p[i] = 6
-------
s[i] = 8 p[i] = 1
-------
s[i] = 3 p[i] = 5
-------
s[i] = 3 p[i] = 1
-------
s[i] = 7 p[i] = 7
-------
Recursive:6
Iteration:6
The following approach might be useful, when bigger numbers are involved (specially for s) and consequently a 2 dimensional array would be unnecessary big and only a few w values would actually be used in computing the result.
The idea: precompute possible w values, by starting at w and for each i in [n, n-1, ..., 1] determine the values w_[i], where w_[i+1] >= s[i] without duplicates.
Then iterate i_n over n and compute sub-results only for valid w_[i] values.
I chose an array of Dictionary as datastructure, since it's relatively easy to design sparse data this way.
public static int DP(int n, int w)
{
// compute possible w values for each iteration from 0 to n
Stack<HashSet<int>> validW = new Stack<HashSet<int>>();
validW.Push(new HashSet<int>() { w });
for (int i = n; i > 0; i--)
{
HashSet<int> validW_i = new HashSet<int>();
foreach (var prevValid in validW.Peek())
{
validW_i.Add(prevValid);
if (prevValid >= s[i])
{
validW_i.Add(prevValid - s[i]);
}
}
validW.Push(validW_i);
}
// compute sub-results for all possible n,w values.
Dictionary<int, int>[] value = new Dictionary<int,int>[n + 1];
for (int n_i = 0; n_i <= n; n_i++)
{
value[n_i] = new Dictionary<int, int>();
HashSet<int> validSubtractW_i = validW.Pop();
foreach (var w_j in validSubtractW_i)
{
if (n_i == 0 || w_j == 0)
value[n_i][w_j] = 0;
else if (s[n_i] > w_j)
value[n_i][w_j] = value[n_i - 1][w_j];
else
value[n_i][w_j] = Math.Max(value[n_i - 1][w_j], (p[n_i] + value[n_i - 1][w_j - s[n_i]]));
}
}
return value[n][w];
}
It's important to understand that some space and computation is "wasted" in order to precompute possible w values and to support the sparse data structures. So this approach might perform bad for large data sets with small values in s, where most w values will be possible sub-results.
After some more thought I realized, if space is a concern, you can actually throw away the sub-results of everything except the previous outer loop iteration, since the recursion in this algorithm follows a strict n-1 pattern. However, I'm not including this into my code for now.
Your approach does not work because your dynamic programmig state space (which apparently is only one variable) does not match the signature of the recursive method. The goal of the dynamic programming approach should be to define and fill a state space such that all results for evaluation are available when needed. On inspection of the recursive method, notice that the recursive calls of F_recursion may change both arguments, n and w. This is an indication that a two-dimensional state space should be used.
The first argument (which apparently limits the range of items) can range from 0 to n while the second argument (which apparently is some bound for the total of an item property) can range from 0 to w.
You should define a two dimensional state space
int[,] value = new int[n,w];
for accomodation of the values. Next, you should initialize the values to undefined; you can use the value Int32.MaxValue for this, because it will behave in a suitable way if the minimum with some different value is calculated.
Next, the iterative version of the algorithm shoud use two loops which iterate in a forwad manner, unlike the recursive iteration which decreases the arguments.
for (int i = 0; i < n; i++)
{
for (int j = 0; j < w; j++)
{
// logic for the recurrence relation goes here
}
}
In the innermost block you can use a modified version of the recurrence relation. Instead of using recursive calls, you access values which are stored in value; instead of returning values, you write the values to value.
Semantically this is the same as memoization, but instead of using actual recursive calls, the order of evaluation asserts that necessary values always exist, making additional logic unneccessary.
Once the state space is filled, you have to examine its last state (namely the part of the array where the first index is n-1) to determine the maximal value for the entire input.
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:
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);
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.