Check if List<Int32> values are consecutive - c#

List<Int32> dansConList = new List<Int32>();
dansConList[0] = 1;
dansConList[1] = 2;
dansConList[2] = 3;
List<Int32> dansRandomList = new List<Int32>();
dansRandomList[0] = 1;
dansRandomList[1] = 2;
dansRandomList[2] = 4;
I need a method that, when evaluating the above lists, will return false for dansRandomList and true for dansConList based on the fact dansConList has a consecutive number sequence in it's values, and dansRandomList does not (missing the value 3).
Using LINQ is preferable, if possible.
What I've Tried:
For the sake of achieving the end result, I have used a for loop and compare with 'i' (loop counter) to evaluate the values, but as mentioned above I'd like to use LINQ for this.

One-liner, only iterates until the first non-consecutive element:
bool isConsecutive = !myIntList.Select((i,j) => i-j).Distinct().Skip(1).Any();
Update: a couple examples of how this works:
Input is { 5, 6, 7, 8 }
Select yields { (5-0=)5, (6-1=)5, (7-2=)5, (8-3=)5 }
Distinct yields { 5, (5 not distinct, 5 not distinct, 5 not distinct) }
Skip yields { (5 skipped, nothing left) }
Any returns false
Input is { 1, 2, 6, 7 }
Select yields { (1-0=)1, (2-1=)1, (6-2=)4, (7-3=)4 } *
Distinct yields { 1, (1 not distinct,) 4, (4 not distinct) } *
Skip yields { (1 skipped,) 4 }
Any returns true
* The Select will not yield the second 4 and the Distinct will not check it, as the Any will stop after finding the first 4.

var min = list.Min();
var max = list.Max();
var all = Enumerable.Range(min, max - min + 1);
return list.SequenceEqual(all);

var result = list
.Zip(list.Skip(1), (l, r) => l + 1 == r)
.All(t => t);

You can use this extension method:
public static bool IsConsecutive(this IEnumerable<int> ints )
{
//if (!ints.Any())
// return true; //Is empty consecutive?
// I think I prefer exception for empty list but I guess it depends
int start = ints.First();
return !ints.Where((x, i) => x != i+start).Any();
}
Use it like this:
[Test]
public void ConsecutiveTest()
{
var ints = new List<int> {1, 2, 4};
bool isConsecutive = ints.IsConsecutive();
}

Extension method:
public static bool IsConsecutive(this IEnumerable<int> myList)
{
return myList.SequenceEqual(Enumerable.Range(myList.First(), myList.Last()));
}
Useage:
bool isConsecutive = dansRandomList.IsConsecutive();

Caveat: returns true if empty.
var list = new int[] {-1,0,1,2,3};
var isConsecutive = list.Select((n,index) => n == index+list.ElementAt(0)).All (n => n);

Here is the another one. It supports {1,2,3,4} and {4,3,2,1} both. It tests sequential number differences equals 1 or -1.
Function IsConsecutive(ints As IEnumerable(Of Integer)) As Boolean
If ints.Count > 1 Then
Return Enumerable.Range(0, ints.Count - 1).
All(Function(r) ints(r) + 1 = ints(r + 1) OrElse ints(r) - 1 = ints(r + 1))
End If
Return False
End Function

In order to check whether the series contain consecutive number or not you may use this
Sample
isRepeatable(121878999, 2);
Result = True
since 9 repeats two times , where upto is no of times in series
isRepeatable(37302293, 3)
Result = False
since no number repeat 3 times in series
static bool isRepeatable(int num1 ,int upto)
{
List<int> myNo = new List<int>();
int previous =0;
int series = 0;
bool doesMatch = false;
var intList = num1.ToString().Select(x => Convert.ToInt32(x.ToString())).ToList();
for (int i = 0; i < intList.Count; i++)
{
if (myNo.Count==0)
{
myNo.Add(intList[i]);
previous = intList[i];
series += 1;
}
else
{
if (intList[i]==previous)
{
series += 1;
if (series==upto)
{
doesMatch = true;
break;
}
}
else
{
myNo = new List<int>();
previous = 0;
series = 0;
}
}
}
return doesMatch;
}

// 1 | 2 | 3 | 4 | _
// _ | 1 | 2 | 3 | 4
// | 1 | 1 | 1 | => must be 1 (or 2 for even/odd consecutive integers)
var numbers = new List<int>() { 1, 2, 3, 4, 5 };
const step = 1; // change to 2 for even and odd consecutive integers
var isConsecutive = numbers.Skip(1)
.Zip(numbers.SkipLast(1))
.Select(n => {
var diff = n.First - n.Second;
return (IsValid: diff == step, diff);
})
.Where(diff => diff.IsValid)
.Distinct()
.Count() == 1;
Or we could write that a bit shorter but less readable:
var isConsecutive = numbers.Skip(1)
.Zip(numbers.SkipLast(1), (l, r) => (IsValid: (l-r == step), l-r))
.Where(diff => diff.IsValid)
.Distinct()
.Count() == 1;

Old question, but here's an easy way using some simple algebra.
This only works if your integers start at 1 though.
public bool AreIntegersConsecutive(List<int> integers)
{
var sum = integers.Sum();
var count = integers.Count();
var expectedSum = (count * (count + 1)) / 2;
return expectedSum == sum;
}

It is works for unique list only.
List<Int32> dansConList = new List<Int32>();
dansConList.Add(7);
dansConList.Add(8);
dansConList.Add(9);
bool b = (dansConList.Min() + dansConList.Max())*((decimal)dansConList.Count())/2.0m == dansConList.Sum();

Here is an extension method that uses the Aggregate function.
public static bool IsConsecutive(this List<Int32> value){
return value.OrderByDescending(c => c)
.Select(c => c.ToString())
.Aggregate((current, item) =>
(item.ToInt() - current.ToInt() == -1) ? item : ""
)
.Any();
}
Usage:
var consecutive = new List<Int32>(){1,2,3,4}.IsConsecutive(); //true
var unorderedConsecutive = new List<Int32>(){1,4,3,2}.IsConsecutive(); //true
var notConsecutive = new List<Int32>(){1,5,3,4}.IsConsecutive(); //false

Here is a C version code, I think it's easy to rewrite it in other language based on the logical.
int isConsecutive(int *array, int length) {
int i = 1;
for (; i < length; i++) {
if (array[i] != array[i - 1] + 1)
return 0; //which means false and it's not a consecutive list
}
return 1;
}

Related

How to dynamically add indexes values of an array in C#?

I have an array where the first two smallest values have to be added, and consequently the result has to be added to next smallest and so on until it reaches the end of the array to give a final total.
However, how can I dynamically modify the method/function so if the values changes and I have 6 vehicles and 6 specs values in the array, the return of the method/function total is not restricted to just 4 indexes.
The array values are unsorted, so in order to add the first smallest, it has to be sorted. Once that's done it adds the values of the new array.
Here's what I've tried:
public static int vehicles = 4;
public static int[] specs = new int[] { 40, 8, 16, 6 };
public static int time(int vehicles, int[] specs)
{
int newValue = 0;
for (int i = 1; i < vehicles; i++)
{
newValue = specs[i];
int j = i;
while (j > 0 && specs[j - 1] > newValue)
{
specs[j] = specs[j - 1];
j--;
}
specs[j] = newValue;
}
// How can I dynamically change this below:
int result1 = specs[0] + specs[1];
int result2 = result1 + specs[2];
int result3 = result2 + specs[3];
int total = result1 + result2 + result3;
return total; // Returns 114
}
Here's the idea of how it works:
4, [40, 8, 16, 6] = 14 --> [40, 14, 16] = 30 --> [40, 30] = 70 ==>> 14 + 30 + 70 = 114
6, [62, 14, 2, 6, 28, 41 ] = 8 --> [62, 14, 8, 28, 41 ] --> 22 [62, 22, 28, 41 ] --> 50
[62, 50, 41 ] --> 91 [62, 91 ] --> 153 ==> 8 + 22 + 50 + 91 + 153 = 324
First off, if you are not restricted to arrays for some weird reason use List<int> and your life will be easier.
List<int> integers = { 14, 6, 12, 8 };
integers.Sort();
integers.Reverse();
while( integers.Count > 1 )
{
int i = integers[integers.Count - 1];
int j = integers[integers.Count - 2];
integers[integers.Count - 2] = i + j;
integers.RemoveAt(integers.Count - 1);
}
var result = integers[0];
P.S.: This can be easily modified to operate on the array version, you can't RemoveAt() from an array but can separately maintain a lastValidIndex.
I would go with the simplest version of a one line solution using LINQ:
Array.Sort(specs);
int total = specs.Select((n, i) => specs.Take(i + 1).Sum()).Sum() - (specs.Length > 1 ? specs[0] : 0);
I would use Linq.
Enumerable.Range(2, specs.Length - 1)
.Select(i => specs
.Take(i)
.Sum())
.Sum();
Explanation:
We take a range starting from 2 ending with specs.Length.
We sum the first i values of specs where i is the current value in the range.
After we have all those sums, we sum them up as well.
To learn more about linq, start here.
This code only works if the values have been sorted already.
If you want to sort the values using linq, you should use this:
IEnumerable<int> sorted = specs.OrderBy(x => x);
Enumerable.Range(2, sorted.Count() - 1)
.Select(i => sorted
.Take(i)
.Sum())
.Sum();
The OrderBy function needs to know how to get the value it should use to compare the array values. Because the array values are the values we want to compare we can just select them using x => x. This lamba takes the value and returns it again.
See comments in code for explanation.
using System;
using System.Linq;
class Program
{
static void Main()
{
//var inputs = new [] { 40, 8, 16, 6 }; // total = 114
var inputs = new[] { 62, 14, 2, 6, 28, 41 }; // total = 324
var total = 0;
var query = inputs.AsEnumerable();
while (query.Count() > 1)
{
// sort the numbers
var sorted = query.OrderBy(x => x).ToList();
// get sum of the first two smallest numbers
var sumTwoSmallest = sorted.Take(2).Sum();
// count total
total += sumTwoSmallest;
// remove the first two smallest numbers
query = sorted.Skip(2);
// add the sum of the two smallest numbers into the numbers
query = query.Append(sumTwoSmallest);
}
Console.WriteLine($"Total = {total}");
Console.WriteLine("Press any key...");
Console.ReadKey(true);
}
}
I benchmark my code and the result was bad when dealing with large dataset. I suspect it was because of the sorting in the loop. The sorting is needed because I need to find the 2 smallest numbers in each iteration. So I think I need a better way to solve this. I use a PriorityQueue (from visualstudiomagazine.com) because the elements are dequeued based on priority, smaller numbers have higher priority in this case.
long total = 0;
while (pq.Count() > 0)
{
// get two smallest numbers when the priority queue is not empty
int sum = (pq.Count() > 0 ? pq.Dequeue() : 0) + (pq.Count() > 0 ? pq.Dequeue() : 0);
total += sum;
// put the sum of two smallest numbers in the priority queue if the queue is not empty
if (pq.Count() > 0) pq.Enqueue(sum);
}
Here's some benchmark results of the new (priority queue) code and the old code in release build. Results are in milliseconds. I didn't test the 1 million data with the old code because it's too slow.
+---------+----------+-------------+
| Data | New | Old |
+---------+----------+-------------+
| 10000 | 3.9158 | 5125.9231 |
| 50000 | 16.8375 | 147219.4267 |
| 1000000 | 406.8693 | |
+---------+----------+-------------+
Full code:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
class Program
{
static void Main()
{
const string fileName = #"numbers.txt";
using (var writer = new StreamWriter(fileName))
{
var random = new Random();
for (var i = 0; i < 10000; i++)
writer.WriteLine(random.Next(100));
writer.Close();
}
var sw = new Stopwatch();
var pq = new PriorityQueue<int>();
var numbers = File.ReadAllLines(fileName);
foreach (var number in numbers)
pq.Enqueue(Convert.ToInt32(number));
long total = 0;
sw.Start();
while (pq.Count() > 0)
{
// get two smallest numbers when the priority queue is not empty
int sum = (pq.Count() > 0 ? pq.Dequeue() : 0) + (pq.Count() > 0 ? pq.Dequeue() : 0);
total += sum;
// put the sum of two smallest numbers in the priority queue if the queue is not empty
if (pq.Count() > 0) pq.Enqueue(sum);
}
sw.Stop();
Console.WriteLine($"Total = {total}");
Console.WriteLine($"Time = {sw.Elapsed.TotalMilliseconds}");
total = 0;
var query = File.ReadAllLines(fileName).Select(x => Convert.ToInt32(x));
sw.Restart();
while (query.Count() > 0)
{
// sort the numbers
var sorted = query.OrderBy(x => x).ToList();
// get sum of the first two smallest numbers
var sumTwoSmallest = sorted.Take(2).Sum();
// count total
total += sumTwoSmallest;
// remove the first two smallest numbers
query = sorted.Skip(2);
// add the sum of the two smallest numbers into the numbers
if (query.Count() > 0)
query = query.Append(sumTwoSmallest);
}
sw.Stop();
Console.WriteLine($"Total = {total}");
Console.WriteLine($"Time = {sw.Elapsed.TotalMilliseconds}");
Console.WriteLine("Press any key...");
Console.ReadKey(true);
}
}
PriorityQueue code:
using System;
using System.Collections.Generic;
// From http://visualstudiomagazine.com/articles/2012/11/01/priority-queues-with-c.aspx
public class PriorityQueue<T> where T : IComparable<T>
{
private List<T> data;
public PriorityQueue()
{
this.data = new List<T>();
}
public void Enqueue(T item)
{
data.Add(item);
int ci = data.Count - 1; // child index; start at end
while (ci > 0)
{
int pi = (ci - 1) / 2; // parent index
if (data[ci].CompareTo(data[pi]) >= 0)
break; // child item is larger than (or equal) parent so we're done
T tmp = data[ci];
data[ci] = data[pi];
data[pi] = tmp;
ci = pi;
}
}
public T Dequeue()
{
// assumes pq is not empty; up to calling code
int li = data.Count - 1; // last index (before removal)
T frontItem = data[0]; // fetch the front
data[0] = data[li];
data.RemoveAt(li);
--li; // last index (after removal)
int pi = 0; // parent index. start at front of pq
while (true)
{
int ci = pi * 2 + 1; // left child index of parent
if (ci > li)
break; // no children so done
int rc = ci + 1; // right child
if (rc <= li && data[rc].CompareTo(data[ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead
ci = rc;
if (data[pi].CompareTo(data[ci]) <= 0)
break; // parent is smaller than (or equal to) smallest child so done
T tmp = data[pi];
data[pi] = data[ci];
data[ci] = tmp; // swap parent and child
pi = ci;
}
return frontItem;
}
public T Peek()
{
T frontItem = data[0];
return frontItem;
}
public int Count()
{
return data.Count;
}
public override string ToString()
{
string s = "";
for (int i = 0; i < data.Count; ++i)
s += data[i].ToString() + " ";
s += "count = " + data.Count;
return s;
}
public bool IsConsistent()
{
// is the heap property true for all data?
if (data.Count == 0)
return true;
int li = data.Count - 1; // last index
for (int pi = 0; pi < data.Count; ++pi)
{ // each parent index
int lci = 2 * pi + 1; // left child index
int rci = 2 * pi + 2; // right child index
if (lci <= li && data[pi].CompareTo(data[lci]) > 0)
return false; // if lc exists and it's greater than parent then bad.
if (rci <= li && data[pi].CompareTo(data[rci]) > 0)
return false; // check the right child too.
}
return true; // passed all checks
}
// IsConsistent
}
// PriorityQueue
Reference:
https://visualstudiomagazine.com/articles/2012/11/01/priority-queues-with-c.aspx
https://en.wikipedia.org/wiki/Priority_queue
You can simply sort it using Array.Sort(), then get the sums in a new array which starts with the smallest value and add each next value to the most recent sum, the total will be the value of the last sum.
public static int time(int vehicles, int[] specs)
{
int i, total;
int[] sums = new int[vehicles];
Array.Sort(spec);
sums[0] = specs[0];
for (i = 1; i < vehicles; i++)
sums[i] = sums[i - 1] + spec[i];
total = sums[spec - 1];
}

Want to find Highest Maximum number and Second Highest Maximum Number with their Index value

This code finds the highest number and second highest number but gives the wrong index number, but only in some cases
When array values: {1,3,3,0,3}
When Array Values: {3,3,0,1,2}
If all are unique numbers then it gives an accurate answer with accurate index value; Where do I need to change the code to get accurate index value for above cases?
FirstMaxNumber=arrFindIndex[0];
SecondMaxNumber=arrFindIndex[0];
FirstMaxRatingIndex=0;
SecondMaxRatingIndex=0;
for (int i = 0; i < arrSize; i++)
{
if (FirstMaxNumber <= arrFindIndex[i])
{
SecondMaxNumber = FirstMaxNumber;
FirstMaxNumber = arrFindIndex[i];
FirstMaxRatingIndex = i;
}
else if (SecondMaxNumber <= arrFindIndex[i])
{
SecondMaxNumber = arrFindIndex[i];
SecondMaxRatingIndex = i;
}
}
// print(FirstMaxNumber);
// Print(FirstMaxRatingIndex);
// print(SecondMaxNumber);
// print(SecondMaxRatingIndex);
In the first if statement, the value of the second maximum value is set:
SecondMaxNumber = FirstMaxNumber;
but the index isn't:
SecondMaxRatingIndex = FirstMaxRatingIndex;
FirstMaxRatingIndex = i;
Something like this:
FirstMaxNumber = arrFindIndex[0];
SecondMaxNumber = arrFindIndex[0];
FirstMaxRatingIndex = 0;
SecondMaxRatingIndex = 0;
// Do not use magic values: "arrSize" but actual length: arrFindIndex.Length
for (int i = 1; i < arrFindIndex.Length; i++) {
int v = arrFindIndex[i];
if (v > FirstMaxNumber) {
// so "first" becomes "second"
SecondMaxNumber = FirstMaxNumber;
SecondMaxRatingIndex = FirstMaxRatingIndex;
FirstMaxNumber = v;
FirstMaxRatingIndex = i;
}
else if ((v > SecondMaxNumber) || (i == 1)) {
SecondMaxNumber = v;
SecondMaxRatingIndex = i;
}
}
Why don't you just use LINQ for that?
var arr = new [] {3, 0, 4, 2, 3, 7};
var min = arr.Select((Val, Key) => new { Val, Key }).First(x => x.Val == arr.Min());
var max = arr.Select((Val, Key) => new { Val, Key }).First(x => x.Val == arr.Max());
Console.WriteLine($"Min Key: {min.Key} Val: {min.Val} \nMax Key: {max.Key} Val: {max.Val}");
// Output
// Min Key: 1 Val: 0
// Max Key: 5 Val: 7
If the arrays are short and you don't particularly care how fast it is, the easiest code is something like this:
var indices = Enumerable.Range(0, array.Length).ToArray();
Array.Sort(array, indices, Comparer<int>.Create((a, b) => b - a));
Then indices will contain the indices of all the elements, in descending order, so you just need the first two.
Here's a compilable console app (requires .Net 4.5 or later):
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
static class Program
{
static void Main()
{
test(1, 3, 3, 0, 3); // Prints 1, 2
test(3, 3, 0, 1, 2); // Prints 0, 1
}
static void test(params int[] array)
{
var indices = Enumerable.Range(0, array.Length).ToArray();
Array.Sort(array, indices, Comparer<int>.Create((a,b)=>b-a));
Console.WriteLine($"{indices[0]}, {indices[1]}");
}
}
}

Get highest number from each row of a triangle and sum it up

I have below triangle of numbers which will be sent as parameter to a function
5
9 6
4 6 8
0 7 1 5
Now this will be received as string in below function with the format 5#9#6#4#6#8#0#7#1#5. So far I've tried to ripple only the digits from #
public class Sample
{
public static string validtrianglesum(string input)
{
string sum="0";
foreach(char num in input)
{
if(!num.Equals('#'))
{
Console.PrintLine(num); //here am getting only the nums excluding #
//How to sum up based on each row
}
}
return sum; //return
}
}
how could highest number from each row and sum them and how could I identify the rows to sum it up? Hope to find some help.
Let's break this down as follows:
Firstly, turn the input into an array of numbers:
string input = "5#9#6#4#6#8#0#7#1#5";
var numbers = input.Split('#').Select(int.Parse).ToArray();
Now let's assume we have a MakeTriangular(int[]) method that turns an array of numbers into a sequence of rows with the first row being of length 1, the second of length 2 and so on, so that it returns IEnumerable<IEnumerable<int>>.
Then we can use that along with Linq to calculate the sum of the maximum value in each row as follows:
int sum = MakeTriangular(numbers).Sum(row => row.Max());
Which gives the answer.
The implementation of MakeTriangular() could look like this:
public static IEnumerable<IEnumerable<int>> MakeTriangular(int[] numbers)
{
for (int i = 0, len = 1; i < numbers.Length; i += len, ++len)
yield return new ArraySegment<int>(numbers, i, len);
}
Putting it all together into a compilable Console app:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
class Program
{
public static void Main()
{
string input = "5#9#6#4#6#8#0#7#1#5";
var numbers = input.Split('#').Select(int.Parse).ToArray();
int sum = MakeTriangular(numbers).Sum(row => row.Max());
Console.WriteLine(sum);
}
public static IEnumerable<IEnumerable<int>> MakeTriangular(int[] numbers)
{
for (int i = 0, len = 1; i < numbers.Length; i += len, ++len)
yield return new ArraySegment<int>(numbers, i, len);
}
}
}
Summing up all values in each row:
private static IEnumerable<int> Sum(string input)
{
int i = 0, s = 0, z = 1;
foreach (var v in input.Split('#').Select(int.Parse))
{
s += v;
if (++i != z) continue;
z++;
yield return s;
s = i = 0;
}
}
The same in one line:
private static IEnumerable<int> Sum(string input) => new Func<int, int, IEnumerable<int>>((i, z) => input.Split('#').Select(int.Parse).GroupBy(e => i++ == z && (i = 1) != null ? ++z : z, e => e).Select(e => e.Sum()))(0, 1);
Summing up all the highest values in each row:
private static int Sum(string input)
{
int i = 0, s = 0, z = 1, m = 0;
foreach (var v in input.Split('#').Select(int.Parse))
{
if (v > m) m = v;
if (++i != z) continue;
z++;
s += m;
i = m = 0;
}
return s;
}
Same in one line:
private static int Sum(string input) => new Func<int, int, int>((i, z) => input.Split('#').Select(int.Parse).GroupBy(e => i++ == z && (i = 1) != null ? ++z : z, e => e).Select(e => e.Max()).Sum())(0, 1);
I am returning the sums as IEnumerable<int> and with the yield return. If you just want to print out the answers change the return type to void and remove the yield return s; line.
One way to solve this is to determine the size of the triangle. By size I mean the height/width. E.g, the provided triangle has a size of 4.
If the size is n then the number of elements in the triangle will be n(n + 1)/2. When the number of elements in the input is known this can be solved to determine n (the size) by solving a second degree polynomial and picking the positive solution (the expression below involving a square root):
var triangle = "5#9#6#4#6#8#0#7#1#5";
var values = triangle.Split('#').Select(Int32.Parse).ToList();
var sizeAsDouble = (-1 + Math.Sqrt(1 + 8*values.Count))/2;
var size = (Int32) sizeAsDouble;
if (sizeAsDouble != size)
throw new ArgumentException("Input data is not a triangle.");
So with the provided input size will be 4. You can then use the size to select each row in the triangle and perform the desired arithmetic:
var maxValues = Enumerable
.Range(0, size)
.Select(i => new { Start = i*(i + 1)/2, Count = i + 1 })
.Select(x => values.Skip(x.Start).Take(x.Count))
.Select(v => v.Max());
The first Select will compute the necessary indices to correctly slice the array of values which is done in the second Select. Again the formula n(n + 1)/2 is used. If you want to you can merge some of these Select operations but I think spliting them up makes it clearer what is going on.
The output of this will be the numbers 5, 9, 8, 7. If you want to sum these you can do it like this:
return maxValues.Sum();
You can use LINQ:
string input = "5#9#6#4#6#8#0#7#1#5";
var nums = input.Split('#').Select(s => Int32.Parse(s));
var res = Enumerable.Range(0, nums.Count())
.Select(n => nums.Skip(Enumerable.Range(0, n).Sum()).Take(n));
.Where(x => x.Any()); // here you have IEnumerable<int> for every row
.Select(arr => arr.Max());
Please give credit to Widi :) but this is your request
var rows = Sum("5#9#6#4#6#8#0#7#1#5");
var total = rows.Sum();
private static IEnumerable<int> Sum(string inp)
{
int i = 0, s = 0, z = 1;
foreach (var v in inp.Split('#').Select(int.Parse))
{
s = Math.Max(s, v);
if (++i == z)
{
z++;
yield return s;
s = i = 0;
}
}
}
I would use 2 functions:
1st one to convert the string into a tree representation:
List<List<int>> GetTree(string data)
{
List<List<int>> CompleteTree = new List<List<int>>();
List<int> ValuesInLine = new List<int>();
int partsinrow = 1;
int counter = 0;
foreach (string part in data.Split('#'))
{
int value = int.Parse(part);
ValuesInLine.Add(value);
if (++counter == partsinrow)
{
CompleteTree.Add(ValuesInLine);
ValuesInLine = new List<int>();
counter = 0;
partsinrow++;
}
}
return CompleteTree;
}
2nd one to sum up the maximum of the lines:
int GetSumOfTree(List<List<int>> tree)
{
int sum = 0;
foreach (List<int> line in tree)
{
line.Sort();
int max = line[line.Count - 1];
sum += max;
}
return sum;
}

LINQ get x amount of elements from a list

I have a query which I get as:
var query = Data.Items
.Where(x => criteria.IsMatch(x))
.ToList<Item>();
This works fine.
However now I want to break up this list into x number of lists, for example 3. Each list will therefore contain 1/3 the amount of elements from query.
Can it be done using LINQ?
You can use PLINQ partitioners to break the results into separate enumerables.
var partitioner = Partitioner.Create<Item>(query);
var partitions = partitioner.GetPartitions(3);
You'll need to reference the System.Collections.Concurrent namespace. partitions will be a list of IEnumerable<Item> where each enumerable returns a portion of the query.
I think something like this could work, splitting the list into IGroupings.
const int numberOfGroups = 3;
var groups = query
.Select((item, i) => new { item, i })
.GroupBy(e => e.i % numberOfGroups);
You can use Skip and Take in a simple for to accomplish what you want
var groupSize = (int)Math.Ceiling(query.Count() / 3d);
var result = new List<List<Item>>();
for (var j = 0; j < 3; j++)
result.Add(query.Skip(j * groupSize).Take(groupSize).ToList());
If the order of the elements doesn't matter using an IGrouping as suggested by Daniel Imms is probably the most elegant way (add .Select(gr => gr.Select(e => e.item)) to get an IEnumerable<IEnumerable<T>>).
If however you want to preserve the order you need to know the total number of elements. Otherwise you wouldn't know when to start the next group. You can do this with LINQ but it requires two enumerations: one for counting and another for returning the data (as suggested by Esteban Elverdin).
If enumerating the query is expensive you can avoid the second enumeration by turning the query into a list and then use the GetRange method:
public static IEnumerable<List<T>> SplitList<T>(List<T> list, int numberOfRanges)
{
int sizeOfRanges = list.Count / numberOfRanges;
int remainder = list.Count % numberOfRanges;
int startIndex = 0;
for (int i = 0; i < numberOfRanges; i++)
{
int size = sizeOfRanges + (remainder > 0 ? 1 : 0);
yield return list.GetRange(startIndex, size);
if (remainder > 0)
{
remainder--;
}
startIndex += size;
}
}
static void Main()
{
List<int> list = Enumerable.Range(0, 10).ToList();
IEnumerable<List<int>> result = SplitList(list, 3);
foreach (List<int> values in result)
{
string s = string.Join(", ", values);
Console.WriteLine("{{ {0} }}", s);
}
}
The output is:
{ 0, 1, 2, 3 }
{ 4, 5, 6 }
{ 7, 8, 9 }
You can create an extension method:
public static IList<List<T>> GetChunks<T>(this IList<T> items, int numOfChunks)
{
if (items.Count < numOfChunks)
throw new ArgumentException("The number of elements is lower than the number of chunks");
int div = items.Count / numOfChunks;
int rem = items.Count % numOfChunks;
var listOfLists = new List<T>[numOfChunks];
for (int i = 0; i < numOfChunks; i++)
listOfLists[i] = new List<T>();
int currentGrp = 0;
int currRemainder = rem;
foreach (var el in items)
{
int currentElementsInGrp = listOfLists[currentGrp].Count;
if (currentElementsInGrp == div && currRemainder > 0)
{
currRemainder--;
}
else if (currentElementsInGrp >= div)
{
currentGrp++;
}
listOfLists[currentGrp].Add(el);
}
return listOfLists;
}
then use it like this :
var chunks = query.GetChunks(3);
N.B.
in case of number of elements not divisible by the number of groups, the first groups will be bigger. e.g. [0,1,2,3,4] --> [0,1] - [2,3] - [4]

Substracting adjacent two values in a list C#

There is a list called cardReaderHistory . That contains some time records in ordered fashion as follows,
InTime1
OutTime1
InTime2
OutTime2
InTime3
OutTime3
InTime4
OutTime4.....furthermore..
What I need is Calculate Working time by (OutTime1 - Intime1) + (OutTime1 - Intime1).....
double
How could I do this in C#...????
double hr = ((outTime1 - inTime1)+(OutTime2 - Intime2)+...);
Thank you..
Poor Beginner
You can filter the input sequence based on the index, and then zip the two sequences:
var inTimes = source.Where((x, index) => index % 2 == 0);
var outTimes = source.Where((x, index) => index % 2 == 1);
var result = inTimes.Zip(outTimes, (inTime, outTime) => outTime - inTime).Sum();
If you don't need the intermediary values, you can also do this:
var result = source.Select((x, index) => (index % 2 == 0) ? -x : x).Sum();
Assuming your cardReaderHistory list is a list of doubles:
List<double> cardReaderHistory = new List<double>(); //fill it somewhere
double result;
for(int i = 0; i < cardReaderHistory.Count(); i++)
{
if(i%2==0) //If it is equal
result -= cardReaderHistory[i];
else //its unequal
result += cardReaderHistory[i];
}
You just loop over your values and add or subtract based on if its even or not.
Something like this...
List<double> l = new List<double> { 1, 2, 3, 4, 5, 6, 7, 8 };
double hr = 0;
for (int i = 0; i < l.Count; i++)
{
hr += i%2 == 0 ? -l[i] : l[i];
}
It seems plausible that the list contains datetimes and not hours. Currently none of the other answers handles that. Here's my take.
var cardReaderHistory = new List<DateTime> {DateTime.Now.AddMinutes(-120), DateTime.Now.AddMinutes(-100), DateTime.Now.AddMinutes(-20), DateTime.Now};
var hours = cardReaderHistory.Split(2).Select(h => (h.Last() - h.First()).TotalHours).Sum();
Split is an extension method
static class ExtentionsMethods
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> seq, int size)
{
while (seq.Any())
{
yield return seq.Take(size);
seq = seq.Skip(size);
}
}
}

Categories