Order reversed in Aggregate LINQ query - linq

I think the result should contain [1,1,2,2,3,3] but it contains [3,3,2,2,1,1]. Why is the list being reversed?
var sequence = new int[] { 1, 2, 3 };
var result = sequence.Aggregate(
Enumerable.Empty<int>(),
(acc, s) => Enumerable.Repeat(s, 2).Concat(acc));
Thanks

For every item in the sequence, you are concatenating the repetition to the beginning of the accumulated sequence. Swap the order so you are concatenating to the end.
(acc, s) => acc.Concat(Enumerable.Repeat(s, 2))
On a side note, it would be easier (and more efficient) to do this to get that sequence instead.
var result =
from s in sequence
from x in Enumerable.Repeat(s, 2)
select x;

Simpler way to achieve by using SelectMany:
var sequence = new int[] { 1, 2, 3 };
var result = sequence.SelectMany(i => new[] {i, i}).ToArray();

Related

Minimum number of steps using only multiply A by 2, or divide A by 2 or increment A by one to go from number A to B

Given two numbers A and B, what is the minimum number of steps to transform number A to become number B.
A step can either be A *= 2, A++ or A /= 2 if and only if A is an even number.
What is the most efficient algorithm to achieve this?
Suppose A and B can be really large numbers.
Here's my take, done in C#.
var a = 2;
var b = 15;
var found = new HashSet<int>() { a };
var operations = new (string operation, Func<int, bool> condition, Func<int, int> projection)[]
{
("/2", x => x % 2 == 0, x => x / 2),
("*2", x => x <= int.MaxValue / 2, x => x *2),
("+1", x => true, x => x + 1),
};
IEnumerable<(int count, string operations, int value)> Project((int count, string operations, int value) current)
{
foreach (var operation in operations)
{
if (operation.condition(current.value))
{
var value = operation.projection(current.value);
if (!found.Contains(value))
{
found.Add(value);
yield return (current.count + 1, $"{current.operations}, {operation.operation}", value);
}
}
}
}
var candidates = new[] { (count: 0, operations: $"{a}", value: a) };
while (!found.Contains(b))
{
candidates =
candidates
.SelectMany(c => Project(c))
.ToArray();
}
var result = candidates.Where(x => x.value == b).First();
Console.WriteLine($"{result.count} operations: {result.operations} = {result.value}");
That outputs:
5 operations: 2, +1, *2, +1, *2, +1 = 15
Basically, this is starting with a at the zeroth step. It then takes this generation and produces all possible values from the operations to create the next generation. If it produces a value that it has already seen it discards the value as there is an equal or faster operation to produce the value. It keeps repeating until b is found.

Getting wrong answer when trying to get k subsets from Array in ActionScript

I'm working on a Texas Holdem game and i need to generate all possible k subsets from an Array of cards (represented as numbers in this example). This is how it looks so far:
public function getKSubsetsFromArray(arr:Array, k:int):Array {
var data:Array = new Array();
var result:Array = new Array();
combinations(arr, data, 0, arr.length - 1, 0, k, result, 0);
return result;
}
public function combinations(arr:Array, data:Array, start:int, end:int, index:int, r:int, resultArray:Array, resultIndex:int):int {
if (index == r) {
trace(resultIndex, data);
resultArray[resultIndex] = data;
return ++resultIndex;
}
for (var i:int = start; i<=end && end-i+1 >= r-index; i++) {
data[index] = arr[i];
resultIndex = combinations(arr, data, i + 1, end, index + 1, r, resultArray, resultIndex);
}
return resultIndex;
}
I am new to Actionscript, my idea is to have a function that takes an array of number and a parameter k, and returns an Array of arrays each of size k. However once i test the functions I get an array containing only the last combination nCk times. For example:
var testArray:Array = new Array(1, 2, 3, 4, 5);
trace(getKSubsetsFromArray(testArray, 3));
Returns:
0 1,2,3
1 1,2,4
2 1,2,5
3 1,3,4
4 1,3,5
5 1,4,5
6 2,3,4
7 2,3,5
8 2,4,5
9 3,4,5
The function output is
3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5
Of course it should print an array containing all the combinations listed before but it only prints the last one the right amount of times.
Thank your for your help.
The reason for the error is that when you are making array of arrays you are actually using the reference of the same array (data) so when the last combination is executed the contains of data array become 3,4,5 and each of index of resultArray points to data array so it prints out same values.
Solution :-
if (index == r) {
trace(resultIndex, data);
var result = new Array();
copy(result,data)
resultArray[resultIndex] = result;
return ++resultIndex;
}
Note :-
The above is pseudo code as i am not familiar with actionscript but you can implement copy function that copies values of data into result in actionscript syntax.

Using LINQ to join [n] collections and find matches

Using LINQ I can find matching elements between two collections like this:
var alpha = new List<int>() { 1, 2, 3, 4, 5 };
var beta = new List<int>() { 1, 3, 5 };
return (from a in alpha
join b in beta on a equals b
select a);
I can increased this to three collections, like so:
var alpha = new List<int>() { 1, 2, 3, 4, 5 };
var beta = new List<int>() { 1, 3, 5 };
var gamma = new List<int>() { 3 };
return (from a in alpha
join b in beta on a equals b
join g in gamma on a equals g
select a);
But how can I construct a LINQ query that will return the matches between N number of collections?
I'm thinking if each collection was added to a parent collection, then the parent collection was iterated through using a recursive loop, it may work?
There's no need to recurse - you can just iterate. However, you may find it best to create a set and intersect that each time:
List<List<int>> collections = ...;
HashSet<int> values = new HashSet<int>(collections[0]);
foreach (var collection in collections.Skip(1)) // Already done the first
{
values.IntersectWith(collection);
}
(Like BrokenGlass, I'm assuming you've got distint values, and that you really just want to find the values which are in all the collections.)
If you prefer the immutable and lazy approach, you could use:
List<List<int>> collections = ...;
IEnumerable<int> values = collections[0];
foreach (var collection in collections.Skip(1)) // Already done the first
{
values = values.Intersect(collection);
}
If you have only unique values you can use Intersect:
var result = alpha.Intersect(beta).Intersect(gamma).ToList();
If you need to preserve multiple values that are not unique you can just exclude non-intersecting items from the original collection as an additional step:
alpha = alpha.Where(x => result.Contains(x)).ToList();
To generalize the Intersect approach you can just use a loop to do all intersections one by one:
IEnumerable<List<int>> collections = new [] { alpha, beta, gamma };
IEnumerable<int> result = collections.First();
foreach (var item in collections.Skip(1))
{
result = result.Intersect(item);
}
result = result.ToList();

LINQ: check whether two list are the same

This should be easy.
I want to check whether two list are the same in that they contain all the same elements or not, orders not important.
Duplicated elements are considered equal, i.e.e, new[]{1,2,2} is the same with new[]{2,1}
var same = list1.Except(list2).Count() == 0 &&
list2.Except(list1).Count() == 0;
Edit: This was written before the OP added that { 1, 2, 2 } equals { 1, 1, 2 } (regarding handling of duplicate entries).
This will work as long as the elements are comparable for order.
bool equal = list1.OrderBy(x => x).SequenceEqual(list2.OrderBy(x => x));
The SetEquals of HashSet is best suited for checking whether two sets are equal as defined in this question
string stringA = "1,2,2";
string stringB = "2,1";
HashSet<string> setA = new HashSet<string>((stringA.Trim()).Split(',').Select(t => t.Trim()));
HashSet<string> setB = new HashSet<string>((stringB.Trim()).Split(',').Select(t => t.Trim()));
bool isSetsEqual = setA.SetEquals(setB);
REFERENCE:
Check whether two comma separated strings are equal (for Content set)
You need to get the intersection of the two lists:
bool areIntersected = t1.Intersect(t2).Count() > 0;
In response to you're modified question:
bool areSameIntersection = t1.Except(t2).Count() == 0 && t2.Except(t1).Count() == 0;
If the count of list1 elements in list2 equals the count of list2 elements in list1, then the lists both contain the same number of elements, are both subsets of each other - in other words, they both contain the same elements.
if (list1.Count(l => list2.Contains(l)) == list2.Count(l => list1.Contains(l)))
return true;
else
return false;

Linq/lambda question about .Select (newby learning 3.0)

I am playing with the new stuff of C#3.0 and I have this code (mostly taken from MSDN) but I can only get true,false,true... and not the real value :
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var oddNumbers = numbers.Select(n => n % 2 == 1);
Console.WriteLine("Numbers < 5:");
foreach (var x in oddNumbers)
{
Console.WriteLine(x);
}
How can I fix that to show the list of integer?
Change your "Select" to a "Where"
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var oddNumbers = numbers.Where(n => n % 2 == 1);
Console.WriteLine("Odd Number:");
foreach (var x in oddNumbers)
{
Console.WriteLine(x);
}
The "Select" method is creating a new list of the lambda result for each element (true/false). The "Where" method is filtering based on the lambda.
In C#, you could also use this syntax, which you may find clearer:
var oddNumbers = from n in numbers
where n % 2 == 1
select n;
which the compiler translates to:
var oddNumbers = numbers.Where(n => n % 2 == 1).Select(n => n);
numbers.Select(n => n % 2 == 1);
Change this to
numbers.Where(n => n % 2 == 1);
What select does is "convert" one thing to another. So in this case, it's "Converting" n to "n % 2 == 1" (which is a boolean) - hence you get all the true and falses.
It's usually used for getting properties on things. For example if you had a list of Person objects, and you wanted to get their names, you'd do
var listOfNames = listOfPeople.Select( p => p.Name );
You can think of this like so:
Convert the list of people into a list of strings, using the following method: ( p => p.Name)
To "select" (in the "filtering" sense of the word) a subset of a collection, you need to use Where.
Thanks Microsoft for the terrible naming

Resources