If you can find a better title, please edit.
I will start by saying I've looked at several q&a's on this topic, mainly this one and this article without having found a way to do this:
Given the word "HALLOWEEN" I would like to find all permutations and combinations for all lengths. The first thing I tried was iterating through the below code giving it length of 1 to begin with and continuing until reaching the length of the word (9).
public static IEnumerable<IEnumerable<T>>
GetPermutations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] {t});
return GetPermutations(list, length - 1)
.SelectMany(t => list.Where(e => !t.Contains(e)),
(t1, t2) => t1.Concat(new T[] {t2}));
}
This gave me unexpected results as the double 'E' and 'L's were omitted, leaving the final set short.
A simpler example could be 'MOM' {M,O,M} where the final set of outcomes would be:
M
O
MO
OM
MM
MOM
MMO
OMM
Notice that I want to see both 'M's as available, but I don't want to see "MMM" as a result. "MOM" would appear twice in the result due to leaving original order (1,2,3) and swapping positions 1 and 3 (3,2,1) would both result in 'M','O','M' but this character sequence only appears once is the result list (which can be done by a string comparison)
Again, with set {1,1,2,3} I would expect to see:
{1,1}
but NOT {2,2} or {3,3}
Here's another solution that should be clear and easily understandable:
public static IEnumerable<string> GetPermutations(string input)
{
if (string.IsNullOrEmpty(input))
{
return new List<string>();
}
var length = input.Length;
var indices = Enumerable.Range(0, length).ToList();
var permutationsOfIndices = GetNumericalPermutations(indices, length);
var permutationsOfInput = permutationsOfIndices.Select(x => new string(x.Select(y => input[y]).ToArray()))
.Distinct();
return permutationsOfInput;
}
private static List<List<int>> GetNumericalPermutations(List<int> values, int maxLength)
{
if (maxLength == 1)
{
return values.Select(x => new List<int>{x}).ToList();
}
else
{
var permutations = GetNumericalPermutations(values, maxLength - 1);
foreach (var index in values)
{
var newPermutations = permutations.Where(x => !x.Contains(index))
.Select(x => x.Concat(new List<int> { index }))
.Where(x => !permutations.Any(y => y.SequenceEqual(x)))
.Select(x => x.ToList())
.ToList();
permutations.AddRange(newPermutations);
}
return permutations;
}
}
For example, the output for "MOM" is:
M
O
OM
MM
MO
MMO
OMM
MOM
I suggest looking at the permutations of the letter positions 0,1,2,3,4,etc mapping those to letters, and then eliminating the duplicates.
Without changing the GetPermutations function, I added another function to get the permutations of the letter positions, map those result to character strings and then eliminate the duplicates.
public void PermutationsTestMethod()
{
GetPermutationsOfString("MOM").ForEach(v => Debug.Print(v));
}
public List<string> GetPermutationsOfString(string value)
{
var resultList = new List<string>();
for (var i = 1; i <= value.Length; i++)
{
var permutations = GetPermutations(Enumerable.Range(0, value.Length), i);
resultList.AddRange(
permutations
.Select(v => new string(v.Select(z => value[z]).ToArray()))
.Distinct()
);
}
return resultList;
}
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetPermutations(list, length - 1)
.SelectMany(t => list.Where(e => !t.Contains(e)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
This works fine:
Func<string, IEnumerable<string>> getAllSubsets = null;
getAllSubsets = x =>
(x == null || !x.Any())
? Enumerable.Empty<string>()
: (x.Length > 1
? getAllSubsets(x.Substring(1))
.SelectMany(y => new [] { y, x.Substring(0, 1) + y })
: new [] { "", x.Substring(0, 1) });
So given getAllSubsets("ABC") I get:
"", "A", "B", "AB", "C", "AC", "BC", "ABC"
And, for your "MOM" example I get:
"", "M", "O", "MO", "M", "MM", "OM", "MOM"
It would be trivial to filter out the empty string and duplicate values if need be, but as it stands it strictly produces all subsets.
I think it is generally better try to avoid generating and eliminating permutations. Text like "aaaaaaaaaaaaaaab" can generate really big amount of duplications.
public static IEnumerable<IEnumerable<T>>
GetPermutationsInner<T>(IEnumerable<IGrouping<T, T>> groupedList, int length)
{
if (length == 1) return groupedList.Select(t => new T[] { t.Key });
return GetPermutationsInner<T>(groupedList, length - 1)
.SelectMany(t => groupedList
.Where(e => t.Count(w => w.Equals(e.Key)) < e.Count())
.Select(s => s.Key),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
public static IEnumerable<IEnumerable<T>>
GetPermutations<T>(IEnumerable<T> list)
{
var resultList = new List<IEnumerable<T>>();
for (int i = 1; i <= list.Count(); ++i)
{
resultList.AddRange(GetPermutationsInner<T>(list.GroupBy(g => g), i));
}
return resultList;
}
Related
The problem is this:
with given integers a and b, return all the possible combinations in the form
±1±2±3±...±a = b
this is my method for it
public static IEnumerable<string> AllCombinationsWithAAndSumOfB(int a, int b)
{
List<string> list= new List<string>();
Func<string, List<string>> newList = y =>
{
var list = new string[2];
list[0] = y + "+";
list[1] = y + "-";
return list.ToList();
};
Func<int, List<string>> AddingToTheLists = x =>
{
list = list.SelectMany(y => newList(y)).ToList();
return list;
};
Func<char, string, int> CharToInt = (x, g) =>
{
return x == '-' ? -(g.IndexOf(x) + 1) : g.IndexOf(x) + 1;
};
return Enumerable.Range(1, a).SelectMany(AddingToTheLists).Where(x => x.Length == a && x.Sum(y => CharToInt(y, x)) <= b);
}
Now, i'm trying to run a test. This is the test.
[Fact]
public void AllCombinationsWithAAndSumOfBWork()
{
string[] list= { "++-", "+-+", "-+-", "--+", "---" };
var result = AllCombinationsWithAAndSumOfB(3, 0);
Assert.Equal(list, result);
}
The problem is the result of the test:
Result Message:
Assert.Equal() Failure
Expected: String[] ["++-", "+-+", "-+-", "--+", "---"]
Actual: WhereEnumerableIterator<String> []
What should i do to stop getting the result WhereEnumerableIterator [] ?
I'm thinking you want all possible combinations of additions and subtractions for a by-one sequentially increasing ordered list, that is of a length, of integers that sum up to b.
For example: If a = 3, and b = 0, then all combinations of additions and subtractions of each of the integers in the following ordered list: 1, 2, 3 should sum to 0.
If so, then the algorithm can be as follows:
public static IEnumerable<string> AllCombinationsWithAAndSumOfB(int a, int b)
{
var numbers = Enumerable.Range(1, a);
var signCombos = Enumerable
.Range(0, Convert.ToInt32("".PadLeft(a, '1'), 2) + 1)
.Select(e => Convert.ToString(e, 2).PadLeft(a, '0').Replace('0', '-').Replace('1', '+'));
var calc = new DataTable();
return signCombos.Select(
signCombo => new
{
signCombo = signCombo,
formula = String.Join("", signCombo.ToCharArray().Zip(numbers, (s, n) => $"{s}{n}"))
})
.Where(si => ((int)calc.Compute(si.formula, null)) == b)
.Select(si => si.signCombo);
}
This returns
--+
++-
Because:
-1 -2 +3 = 0
+1 +2 -3 = 0
I have a list of values. lets say they're {1,2,3,4,5}
and I want to find the combination that sums closest to a given value
so for example if i entered 8 then the function could return
either {3,5} or {1,3,4}. either of those would be exact and i would just take the one with the least indexes 3+5
if there isn't a value that is exact for example 9.45 it would return the value
closest without going over the threshold {4,5}
I'm not sure where i would even start with this. i think it may be possible with a linq query...
static IEnumerable<int> GetClosestValues(IReadOnlyList<int> c, int t)
{
var s=0m;
return c.Select((x, i) => i).OrderByDescending(i => c[i]).Where(i => (s += c[i]) <= t).OrderBy(i => i);
}
Seems to work... not optimized though
The key is just to find all permutations of the set, and then filter (less or equal than threshold value) and order (by distance to threshold value, then by size of the set) them via LINQ:
var source = Enumerable.Range(1, 5).Select(x => (double)x).ToArray();
var permutations = Enumerable.Range(1, source.Length)
.SelectMany(x => Utils.GetOrderedPermutations(source, x))
.Dump();
var threshold = 9.45;
var result = permutations
.Select(x => x.ToArray())
.Select(x => new { Set = x, Sum = x.Sum() })
.Where(x => x.Sum <= threshold)
.OrderBy(x => threshold - x.Sum)
.ThenBy(x => x.Set.Length)
.FirstOrDefault()
.Dump();
GetOrderedPermutations is taken from this answer:
public class Utils
{
public static IEnumerable<T> Yield<T>(T value)
{
yield return value;
}
public static IEnumerable<IEnumerable<T>> GetOrderedPermutations<T>(IEnumerable<T> source, int k)
{
if (k == 0) return new[] { Enumerable.Empty<T>() };
int length = source.Count();
if (k == length) return new[] { source };
if (k > length) return Enumerable.Empty<IEnumerable<T>>();
return GetOrderedHelper<T>(source, k, length);
}
private static IEnumerable<IEnumerable<T>> GetOrderedHelper<T>(IEnumerable<T> source, int k, int length)
{
if (k == 0)
{
yield return Enumerable.Empty<T>();
yield break;
}
int i = 0;
foreach (var item in source)
{
if (i + k > length) yield break;
var permutations = GetOrderedHelper<T>(source.Skip(i + 1), k - 1, length - i);
i++;
foreach (var subPerm in permutations)
{
yield return Yield(item).Concat(subPerm);
}
}
}
}
How do I return a list of the 3 lowest values in another list. For example, I want to get the 3 lowest values like this:
in_list = [2, 3, 4, 5, 6, 1]
To this:
out_list: [2, 3, n, n, n, 1]
Maybe a function like this:
out_list = function(in_list, 3)?
in_list and ouput list is declared like this:
List<string> in_list = new List<string>();
List<string> out_list = new List<string>();
Can you help me developing a C# code for this? Further explanation can be given.
If you really want those weird n, there's this simple solution:
public static List<string> Function(List<string> inputList, int max)
{
var inputIntegers = inputList
.Select(z => int.Parse(z))
.ToList();
var maxAuthorizedValue = inputIntegers
.OrderBy(z => z)
.Take(max)
.Last();
return inputIntegers
.Select(z => z <= maxAuthorizedValue ? z.ToString() : "n")
.ToList();
}
public static void Main(string[] args)
{
List<string> in_list = new List<string> { "2", "3", "4", "6", "1", "7" };
var res = Function(in_list, 3);
Console.Read();
}
For your new requirement about duplicates, you could limit the max number of integer your return:
public static List<string> Function(List<string> inputList, int max)
{
var inputIntegers = inputList.Select(z => int.Parse(z)).ToList();
var maxAuthorizedValue = inputIntegers
.OrderBy(z => z)
.Take(max)
.Last();
// I don't really like that kind of LINQ query (which modifies some variable
// inside the Select projection), so a good old for loop would probably
// be more appropriated
int returnedItems = 0;
return inputIntegers.Select(z =>
{
return (z <= maxAuthorizedValue && ++returnedItems <= max) ? z.ToString() : "n";
}).ToList();
}
You need two queries, one to determine the lowest items and one to fill the result-list. You can use a HashSet for faster loookups:
var lowest = new HashSet<String>(in_list
.Select(s => new { s, val = int.Parse(s) })
.OrderBy(x => x.val)
.Take(3)
.Select(x => x.s));
List<string> out_list = in_list.Select(s => lowest.Contains(s) ? s : "n").ToList();
If you actually only want 3 and duplicates are possible this is the best i've come up with:
var lowest = new HashSet<String>(in_list
.Select(s => new { s, val = int.Parse(s) })
.Distinct()
.OrderBy(x => x.val)
.Take(3)
.Select(x => x.s));
List<string> out_list = in_list
.Select((str, index) => new { str, index, value = int.Parse(str) })
.GroupBy(x => x.str)
.SelectMany(g => lowest.Contains(g.Key)
? g.Take(1).Concat(g.Skip(1).Select(x => new { str = "n", x.index, x.value }))
: g.Select(x => new { str = "n", x.index, x.value }))
.OrderBy(x => x.index)
.Select(x => x.str)
.ToList();
You could use Aggregate to grab a Dictionary of each element with its corresponding number of allowed occurrences which you could then use to grab your values from the input list:
public static List<string> GetList(List<string> in_list, int max)
{
Dictionary<string, int> occurrences = new Dictionary<string, int>();
int itemsAdded = 0;
in_list.OrderBy(x => x).Aggregate(occurrences, (list, aggr) =>
{
if (itemsAdded++ < max)
{
if (occurrences.ContainsKey(aggr))
occurrences[aggr]++;
else
occurrences.Add(aggr, 1);
}
return list;
});
//occurrences now contains only each required elements
//with the number of occurrences allowed of that element
List<string> out_list = in_list.Select(x =>
{
return (occurrences.ContainsKey(x) && occurrences[x]-- > 0 ? x : "n");
}).ToList();
return out_list;
}
I have an array string[] with values that are mostly convertible to integers.
var values = new [] {"", "1", "2", "a", "3"};
I need to convert values to an array of integers, discarding any items that aren't convertible. So I end up with
var numbers = new [] {1, 2, 3};
What would be the most efficient (quickest and clean code) way to do this?
var numbers = values.Select(
s => {
int n;
if (!int.TryParse((s ?? string.Empty), out n))
{
return (int?)null;
}
return (int?)n;
}
)
.Where(n => n != null)
.Select(n => n.Value)
.ToArray();
Here is my take on this. It uses a separate method but cleanly expresses the conditional parse without using nullable values:
private static IEnumerable<int> ParseInt32s(IEnumerable<string> value)
{
foreach(var value in values)
{
int n;
if(Int32.TryParse(value, out n))
{
yield return n;
}
}
}
Usage:
string[] values;
var parsedValues = ParseInt32s(values).ToArray();
I personally use an extension method that's a little different from what others have posted so far. It specifically uses a custom WeakConverter<TSource, TResult> delegate to avoid the issue in Ron's answer of calling ToString() on every object, while maintaining genericity unlike Jared's answer (though I will concede that sometimes trying to make everything generic is overdoing it -- but in this case, the added effort is really not much for what I consider a significant benefit in terms of reusability).
public delegate bool WeakConverter<TSource, TResult>(TSource source, out TResult result);
public static IEnumerable<TResult> TryConvertAll<TSource, TResult>(this IEnumerable<TSource> source, WeakConverter<TSource, TResult> converter)
{
foreach (TSource original in source)
{
TResult converted;
if (converter(original, out converted))
{
yield return converted;
}
}
}
With this in place, you can convert a string[] to an int[] quite simply and robustly (no double-parsing necessary):
string[] strings = new[] { "1", "2", "abc", "3", "", "123" };
int[] ints = strings.TryConvertAll<string, int>(int.TryParse).ToArray();
foreach (int x in ints)
{
Console.WriteLine(x);
}
Output:
1
2
3
123
This can be done in a single linq statement without having to do the parse twice:
var numbers = values
.Select(c => { int i; return int.TryParse(c, out i) ? i : (int?)null; })
.Where(c => c.HasValue)
.Select(c => c.Value)
.ToArray();
EDIT: Updated to not use try/catch, since StackOverflow users have pointed out that it's slow.
Try this.
var values = new[] { "", "1", "2", "a", "3" };
List<int> numeric_list = new List();
int num_try = 0;
foreach (string string_value in values)
{
if (Int32.TryParse(string_value, out num_try) {
numeric_list.Add(num_try);
}
/* BAD PRACTICE (as noted by other StackOverflow users)
try
{
numeric_list.Add(Convert.ToInt32(string_value));
}
catch (Exception)
{
// Do nothing, since we want to skip.
}
*/
}
return numeric_list.ToArray();
You could try the following
public static IEnumerable<int> Convert(this IEnumerable<string> enumerable) {
Func<string,int?> convertFunc = x => {
int value ;
bool ret = Int32.TryParse(x, out value);
return ret ? (int?)value : null;
};
return enumerable
.Select(convertFunc)
.Where(x => x.HasValue)
.Select(x => x.Value);
}
This can easily then be converted to an array.
var numbers = values.Convert().ToArray();
With some straightforward LINQ:
var numbers = values.Where(x => { int num = 0; return Int32.TryParse(x, out num); })
.Select(num => Int32.Parse(num));
Notably this converts every string twice. Doing this imperatively you'll lose some clarity but gain some speed (as an IEnumerable extension):
public static IEnumerable<int> TryCastToInt<T>(this IEnumerable<T> values)
int num = 0;
foreach (object item in values) {
if (Int32.TryParse(item.ToString(), num)) {
yield return num;
}
}
}
int n;
var values = new[] { "", "1", "2", "a", "3" };
var intsonly = values.Where (v=> Int32.TryParse(v, out n)).Select(x => Int32.Parse(x));
var numbers = values
.Where(x => !String.IsNullOrEmpty(x))
.Where(x => x.All(Char.IsDigit))
.Select(x => Convert.ToInt32(x))
.ToArray();
Is there a quick and nice way using linq?
How about:
var most = list.GroupBy(i=>i).OrderByDescending(grp=>grp.Count())
.Select(grp=>grp.Key).First();
or in query syntax:
var most = (from i in list
group i by i into grp
orderby grp.Count() descending
select grp.Key).First();
Of course, if you will use this repeatedly, you could add an extension method:
public static T MostCommon<T>(this IEnumerable<T> list)
{
return ... // previous code
}
Then you can use:
var most = list.MostCommon();
Not sure about the lambda expressions, but I would
Sort the list [O(n log n)]
Scan the list [O(n)] finding the longest run-length.
Scan it again [O(n)] reporting each number having that run-length.
This is because there could be more than one most-occurring number.
Taken from my answer here:
public static IEnumerable<T> Mode<T>(this IEnumerable<T> input)
{
var dict = input.ToLookup(x => x);
if (dict.Count == 0)
return Enumerable.Empty<T>();
var maxCount = dict.Max(x => x.Count());
return dict.Where(x => x.Count() == maxCount).Select(x => x.Key);
}
var modes = { }.Mode().ToArray(); //returns { }
var modes = { 1, 2, 3 }.Mode().ToArray(); //returns { 1, 2, 3 }
var modes = { 1, 1, 2, 3 }.Mode().ToArray(); //returns { 1 }
var modes = { 1, 2, 3, 1, 2 }.Mode().ToArray(); //returns { 1, 2 }
I went for a performance test between the above approach and David B's TakeWhile.
source = { }, iterations = 1000000
mine - 300 ms, David's - 930 ms
source = { 1 }, iterations = 1000000
mine - 1070 ms, David's - 1560 ms
source = 100+ ints with 2 duplicates, iterations = 10000
mine - 300 ms, David's - 500 ms
source = 10000 random ints with about 100+ duplicates, iterations = 1000
mine - 1280 ms, David's - 1400 ms
Here is another answer, which seems to be fast. I think Nawfal's answer is generally faster but this might shade it on long sequences.
public static IEnumerable<T> Mode<T>(
this IEnumerable<T> source,
IEqualityComparer<T> comparer = null)
{
var counts = source.GroupBy(t => t, comparer)
.Select(g => new { g.Key, Count = g.Count() })
.ToList();
if (counts.Count == 0)
{
return Enumerable.Empty<T>();
}
var maxes = new List<int>(5);
int maxCount = 1;
for (var i = 0; i < counts.Count; i++)
{
if (counts[i].Count < maxCount)
{
continue;
}
if (counts[i].Count > maxCount)
{
maxes.Clear();
maxCount = counts[i].Count;
}
maxes.Add(i);
}
return maxes.Select(i => counts[i].Key);
}
Someone asked for a solution where there's ties. Here's a stab at that:
int indicator = 0
var result =
list.GroupBy(i => i)
.Select(g => new {i = g.Key, count = g.Count()}
.OrderByDescending(x => x.count)
.TakeWhile(x =>
{
if (x.count == indicator || indicator == 0)
{
indicator = x.count;
return true;
}
return false;
})
.Select(x => x.i);
Here's a solution I've written for when there are multiple most common elements.
public static List<T> MostCommonP<T>(this IEnumerable<T> list)
{
return list.GroupBy(element => element)
.GroupBy(group => group.Count())
.MaxBy(groups => groups.Key)
.Select(group => group.Key)
.ToList();
}