Best sequence using LINQ - c#

I have ordered list like in example
var someList = new List<int>{1,1,2,3,5,2,1,3,7,1};
I want to select by using LINQ best(highest sum) sequence of 3 numbers.
In this case answer is 3,7,1 or 1,3,7. Is that possible without change order or sorting?
I have an idea how to do this without LINQ, but I just wanna know to do with LINQ

You can use Skip/Zip to end up with triples. For example:
var triples = list.Zip(list.Skip(1).Zip(list.Skip(2), (b, c) => new { b, c }),
(a, bc) => new { a, bc.b, bc.c });
(That may have some errors - I haven't tested it yet.)
You can then order those triples pretty easily:
var orderedTriples = triples.OrderByDescending(t => t.a + t.b + t.c);
If you're using the triples in multiple contexts, you might want to write an extension method to use Tuple<,,> instead:
public static IEnumerable<Tuple<T, T, T>> InTriples<T>(this IEnumerable<T> source)
{
// Or potentially write custom code to do this. It wouldn't be too hard...
return source.Zip(list.Skip(1).Zip(list.Skip(2), (b, c) => new { b, c }),
(a, bc) => Tuple.Create(a, bc.b, bc.c));
}
As for whether LINQ is suitable for this - having the InTriples method generally available means that the rest of the code becomes pretty simple. Using Skip/Zip isn't going to be terribly efficient, but once you've got the code going using that, you can easily rewrite the InTriples method to use an iteerator block instead.

Alternative solution with summing into list directly, without creating triples:
var bestIndex = someList.Zip(someList.Skip(1), (a, b) => a + b)
.Zip(someList.Skip(2), (a, b) => a + b)
.Select((v, i) => new
{
Value = v,
Index = i
})
.OrderByDescending(x => x.Value )
.First()
.Index;

seems to return first highest sequence
using System;
using System.Collections.Generic;
using System.Linq;
namespace take3highestsum
{
class Program
{
static void Main(string[] args)
{
//question sequence
List<int> intlist = new List<int> { 1, 1, 2, 3, 5, 2, 1, 3, 7, 1 };
//display in console stuff not part of answer
foreach (int a in intlist)
{
Console.Write(a + " ");
}
Console.WriteLine();
//begin answer
//check for legit list since we need at least 3 elements
if (intlist.Count < 3) { throw new Exception("List must have more than 3 elements"); }
//stuff we will need
int lastindx = intlist.Count - 1, baseindex = -1;
//begin LINQ
int[] result = intlist.Select(a =>
{
baseindex++;//increment
//return each sequence of three numbers
return new int[]{
intlist[baseindex],//always base index
baseindex + 1 > lastindx ? 0 : intlist[baseindex + 1], //base index + 1 or 0 if out of bounds
baseindex + 2 > lastindx ? 0 : intlist[baseindex + 2] };//base index + 2 or 0 if out of bounds
}).OrderByDescending(b => b.Sum()).First();
//end LINQ
//end answer
//stuff to display proof
foreach (int a in result)
{
Console.Write(a);
}
Console.ReadLine();
}
}
}

Related

Return IEnumerable with Linq based on choice

I am trying to figure out a way to solve this issue with Linq, does someone have any idea on how to do this? Trying to find this particular use case has proven to be quite challenging so I hope this question hasn't been asked before even though I suspect I just couldn't find it.
public class Test
{
public int a;
public int b;
}
public Test[] testArray;
public enum Choice { A,B, Both = A|B }
public IEnumerable<int> GetEnumerable(Choice choice)
{
//need to use Linq methods to return an enumerable based on choice
}
//e.g testArray = { (1,2) (3,4) (5,6)
//calling GetEnumerable(Choice.A)
// 1,3,5
//calling GetEnumerable(Choice.Both)
// 1,2,3,4,5,6
Everyone focused on the wrong aspects of my question, yes the [Flags] attribute is missing, yes the enum items should be a power of 2 to be used as Flags.
I already marked the correct answer which is to loop over the collection which is what I did before, I just didn't realize I could yield return a IEnumerable so Implemented an enumerator
All the other solutions use Linq but rely too much on instantiating new objects, for a lazy quick approach that is fine but that's not what I wanted.
No Linq is needed, I would maybe use a switch expression (though there is a smattering of Linq in here):
public IEnumerable<int> GetEnumerable(Choice choice)
=> choice switch
{
Choice.A => testArray.Select(a => a.Item1),
Choice.B => testArray.Select(a => a.Item2),
Choice.Both => testArray.SelectMany(a => new[] { a.Item1, a.Item2 }),
_ => throw new ArgumentException("Invalid choice")
};
Theres an inherit problem with your enum, A|B == B, so I changed Both to be it's own case. This solves the problem with one linq query:
public enum Choice { A, B, Both}
public class Test
{
public int A;
public int B;
public Test(int a, int b)
{
A = a;
B = b;
}
}
public class Program
{
public static void Main()
{
var tests = new List<Test>()
{
new Test(1, 2),
new Test(3, 4),
new Test(5, 6)
};
Console.WriteLine(string.Join(", ", GetEnumerable(tests, Choice.A)));
Console.WriteLine(string.Join(", ", GetEnumerable(tests, Choice.B)));
Console.WriteLine(string.Join(", ", GetEnumerable(tests, Choice.Both)));
/*
* Console Output:
* 1, 3, 5
* 2, 4, 6
* 1, 2, 3, 4, 5, 6
*/
}
private static IEnumerable<int> GetEnumerable(IEnumerable<Test> data, Choice choice)
=> data.SelectMany(d => choice switch
{
Choice.A => new List<int> { d.A },
Choice.B => new List<int> { d.B },
Choice.Both => new List<int> { d.A, d.B },
_ => throw new ArgumentException($"No case exists for Choice enum {choice}")
});
}
If you insist on single Linq query, you can try SelectMany where you can return a required collection to be flatten e.g.
public IEnumerable<int> GetEnumerable(Choice choice) => testArray
.SelectMany(item => choice == Choice.Both ? new int[] {item.A, item.B} :
choice == Choice.A ? new int[] {item.A} :
choice == Choice.B ? new int[] {item.B} :
new int[] {});
However, I'd rather implement a simple foreach loop without any Linq:
// Since you use bit combinations, let's do it explicit with [Flags] attribute
[Flags]
public enum Choice {
None = 0, // let have "None" explicit
A = 1,
B = 2,
Both = A|B
}
public IEnumerable<int> GetEnumerable(Choice choice) {
foreach (var item in testArray) {
if (choice.HasFlag(Choice.A))
yield return item.A;
if (choice.HasFlag(Choice.B))
yield return item.B;
}
}

Determine lower value from a list using LINQ in C#

I have a list with four double values in it
var numbers2 = new List<double>() { 2, 3, 9, 7 };
I need to get lower value between the first 2 indexes (2 and 3).
Similarly I need to get lower value between index 3 and 4 (9 and 7)
Is there a way in C sharp to determine this using LINQ?
Once I have the lower value from above list i.e 2 and 7; I need to pass these values in the below loop
for (int i = 0; i < 1; i++)
{
dac[i] = SetValue(lowerValue[j]);
}
if i == 0, I want lowerValue[j] = 2. If i == 1, I want lowerValue[j] = 7
Well as others have pointed out, it doesn't seem like there's any reason to use linq. But if you absolutely had to find some way to do it, then it's possible. I'll throw 3 options out, the last one being linq.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var numbers2 = new List<double>() { 2, 3, 9, 7 };
// you stated it's always 4 values. There's no reason to use linq. The optimal solution would
// be a variation of this (with some constant values instead of magic numbers)..
var first = Math.Min(numbers2[0],numbers2[1]);
var second = Math.Min(numbers2[2],numbers2[3]);
Console.WriteLine($"Lower values: {first},{second}");
// if it was an arbitry sized list (but always even count) you could use a iterator method
var listOfLowerValues = ToPairs(numbers2);
var values = string.Join(",", listOfLowerValues.Select(x => x.ToString()));
Console.WriteLine($"Lower values: {values}");
// finally if you absolutely had too, you can make it even more inefficient
// by using linq.
var indexes = Enumerable.Range(0, numbers2.Count);
var indexed = numbers2.Zip(indexes, (n,i) => (index: i, num: n));
var odd = indexed.Where(x => x.index%2 == 0).Select(x => x.num).ToArray();
var even = indexed.Where(x => x.index%2 > 0).Select(x => x.num).ToArray();
var lower = even.Zip(odd,(v1,v2)=> v1 < v2 ? v1 : v2);
var valuesByLinq = string.Join(",",lower.Select(x => x.ToString()));
Console.WriteLine($"Lower values: {valuesByLinq}");
}
static IEnumerable<double> ToPairs(IEnumerable<double> source)
{
int index = 0;
double previous = 0;
foreach(var n in source)
{
if(index++%2 > 0)
{
yield return (previous < n) ? previous : n;
}
else
{
previous = n;
}
}
}
}

CS7036 C# in Array.FindAll + Lambda

I want to change A to B.
A is
int[] list = { 1, 2, 3, 4, 5 };
List<int> evenList = new List<int>();
foreach ( var item in list )
{
if (item % 2 == 0)
{
evenList.Add(item);
}
}
foreach ( var item in evenList )
{
Console.Write(item + ",");
}
and B is
List<int> evenList = list.FindAll((elem) => elem % 2 == 0);
evenList.ForEach(elem) => { Console.Write(elem + ","); } );
but at B, I faced an Error like this:
CS7036 C# There is no argument given that corresponds to the required
formal parameter 'match' of 'Array.FindAll<T>(T[], Predicate<T>)'
ps. I added using
using System;
using System.Collections.Generic;
Is there anything that I forgot?
int[] list = { 1, 2, 3, 4, 5 };
List<int> evenList = Array.FindAll(list, elem => elem % 2 == 0).ToList();
evenList.ForEach(elem => { Console.Write(elem + ","); } );
Array.FindAll is not extension method, so you simply can't call list.FindAll()
Array do not have ForEach, so you need to cast evenList ToList()
That's because Array.FindAll is static, so you should call it like this:
var NewList = Array.FindAll(list, (elem) => elem %2 == 0);
From MSDN:
Syntax:
public static T[] FindAll<T>(
T[] array,
Predicate<T> match
)
link: https://msdn.microsoft.com/en-us/library/1kkxfxdd(v=vs.110).aspx
Cheers
EDIT:
Programming is not a guessing game where you try to write code without respecting the proper syntax.
Here's what you should be doing:
int[] list = { 1, 2, 3, 4, 5 };
List<int> evenList = Array.FindAll(list, elem => elem % 2 == 0).ToList();
Console.Write(string.Join(",", evenList) );
Any reason why you aren't using Linq? It is newer and applies to any type of collection, not just int[].
using System.Linq;
Console.Write(list
.Where(i => i % 2 == 0)
.Select(i => i.ToString())
.DefaultIfEmpty()
.Aggregate((a, b) => a + "," + b));
Performancewise, this will execute at the same complexity as your for loop, but it will likely be slightly slower overall (though I actually think it won't be that much slower). Linq evaluates lazily which helps here.

C# using LINQ to limit a recursive list

I'm trying to figure out how to use LINQ to limit a recursive call.
My intention with the following code is to run through a list of numbers (num) and for each number recursively count/print up to a set amount (6).
the sequence in newnum that I'm trying to get is : 3 4
5
1
2
3
4
5
5
2
3
4
5
but naturally I'm running into an infinite loop instead. The .Where predicate isn't stopping the loop as I had thought and it's probable my base case is off. Any insight as to the proper way to set this up? Thank you.
var num = new[] {3, 1, 8, 5, 2};
Func<int, int> writeString = delegate(int count)
{
Func<int, int> recursiveWrite = null;
recursiveWrite = n =>
{
Console.WriteLine("string " + n);
recursiveWrite(n+1);
return n;
};
return recursiveWrite(count);
};
var newnum = num.Where(n => writeString(n) < 6); // is this possible?
newnum.ToList().ForEach( w => Console.WriteLine(w));
I noticed that a similar stopping pattern occurs in the following sample code, the .Where will only include factorials less than 7, what am I missing?
var numbers = new[] { 5,1,3,7,2,6,4};
Func<int, int> factorial = delegate(int num) {
Func<int, int> locFactorial = null;
locFactorial = n => n == 1 ? 1 : n * locFactorial(n - 1);
return locFactorial(num);
};
var smallnums = numbers.Where(n => factorial(n) < 7);
The answer is that you don't have a base case. Once your recursive function is executed, there is nothing to stop it - LINQ doesn't perform any kind of magic that can modify the internal logic of another function.
In the example you are missing this key bit of code that will stop the recursion - the base case:
locFactorial = n => n == 1 ? 1 : n * locFactorial(n - 1);
The ternary operator checks to see if n==1 - if it is, it returns 1. This is the base case that your function lacks.
There is no way to provide a base-case to your function through LINQ alone. You need to build this into the recursive function.
Additionally, you are returning the wrong type from your recursive function if you want to return a list of numbers from a single number: this is fundamentally a different case from the Factorial function which returns a single number given a single number.
Here is a function that does what you require without using recursion:
void Main()
{
var numbers = new[] {3, 1, 8, 5, 2};
numbers.SelectMany(x => GetIncreasing(x).TakeWhile(y => y < 6));
}
IEnumerable<int> GetIncreasing(int x)
{
while (true)
yield return x++;
}
You could just stick with generating sequences that fits your requirements, something like:
var num = new[] { 3, 1, 8, 5, 2 };
var limit = 6;
var query = from n in num
where n < limit // sanity check
from pn in Enumerable.Range(n, limit - n)
select pn;
Decent performance and clean code
The difference with the factorial sample is the placing of the end condition. This is what you should do:
recursiveWrite = n =>
{
Console.WriteLine("string " + n);
if (n < 6)
recursiveWrite(n+1);
return n;
};
Not completely sure of what you are trying to achieve but I hope this willl help.
You need a stop condition in your recursive lambda (as n==1 in factorial).
With nested funcs, you can inject this limit "dynamically".
class Program
{
static void Main(string[] args)
{
var num = new[] { 3, 1, 8, 5, 2 };
Func<int, Func<int, IEnumerable<int>>> writeString =
delegate(int maxcount)
{
Func<int, IEnumerable<int>> recursiveWrite = null;
recursiveWrite = (n) =>
{
if (n < maxcount)
{
Console.WriteLine("string " + n);
var rec = recursiveWrite(n + 1);
return new List<int>(){n}.Concat(rec);
}
return new List<int>();
};
return recursiveWrite;
};
var newnum = num.SelectMany(n => writeString(6)(n)); // is this possible?
newnum.ToList().ForEach(w => Console.WriteLine(w));
Console.ReadLine();
}
}

Adding/summing two arrays

I've encountered a purely hypothetical problem which feels like it has an easy solution if I find the right linq method...
I have two arrays of ints and I know they are the same size. I want to create a third array of the same size where the elements in the third array are the sum of the elements in the first two arrays in the corresponding position.
Below is a method that should show what I want to do.
public static int[] AddArrays(int[] a, int[] b)
{
int[] newArray = new int[a.Length];
for (int i = 0; i<a.Length; i++)
{
newArray[i]=a[i]+b[i];
}
return newArray;
}
Are there any Linq methods that I can just use like
return a.DoStuff(b, (x,y) => x+y)
or something like that?
I should note that this probably falls in the category of homework since the original problem came from a website I was looking at (though I can't find a direct link to the problem) and not as a question I need for work or anything.
If no simple method exists then what is the most Linqy way to do this? an array.each would seem to have the problem of not being able to index the second array easily to add the values to the one you are iterating through leading me to wonder if Linq would be any help at all in that situation...
Zip it :)
var a = new int[] {1,2,3 };
var b = new int[] {4,5,6 };
a.Zip(b, (x, y) => x + y)
You can use the Select method.
int[] a = new[] { 1, 2, 3 };
int[] b = new[] { 10, 20, 30 };
var c = a.Select ((x, index) => x + b[index]).ToArray();
public static int[] AddArrays(int[] a, int[] b)
{
return a.Zip(b, (x,y) => x+y).ToArray();
}
IList<int> first = new List<int> { 2, 3, 4, 5 };
IList<int> second = new List<int> { 2, 3, 4, 5 };
var result = Enumerable.Zip(first, second, (a, b) => a + b);
Without LINQ:
private static IEnumerable<int> AddArrays(IEnumerable<int> a1, IEnumerable<int> a2)
{
var e1 = a1.GetEnumerator();
var e2 = a2.GetEnumerator();
while (e1.MoveNext() && e2.MoveNext())
yield return e1.Current + e2.Current;
}
If you have an IEnumerable<int[]> arrayCollection to sum:
arrayCollection.Aggregate((a,b) => a.Zip(b, (x,y) => x + y).ToArray())

Categories

Resources