Finding the sum of each array in a jagged array C# - c#

Im looking to receive a jagged array of type int[][] and then run through the arrays to find the specific array with the highest sum and then return that sum. Ive done some digging online and haven't found much info about how to sum up each array individually.
For example if this was the received input:
int[][] accounts = new int[3][];
accounts[0] = new int[] { 1, 2, 3};
accounts[1] = new int[] { 2, 3, 4 };
accounts[2] = new int[] { 3, 4, 5 };
The closest I've come to this was getting the total sum of all elements
for (var i = 0; i < accounts.Length; i++)
{
for (var j = 0; j < accounts[i].Length; j++)
{
sum += accounts[i][j];
}
}
What step am I missing to separate the arrays and sum them up individually?

Your issue is you are not keeping a max value around.
Given
var accounts = new int[][]
{
new[] {1, 2, 3},
new[] {2, 3, 4},
new[] {3, 4, 5}
};
Example
var max = 0;
for (var i = 0; i < accounts.Length; i++)
{
var sum = 0;
for (var j = 0; j < accounts[i].Length; j++)
sum += accounts[i][j];
if (sum > max)
max = sum;
}
However, let's see how we can make this more succinct.
You could use foreach
foreach (var array in accounts)
{
var sum = 0;
foreach (var item in array)
sum += item;
if (sum > max)
max = sum;
}
You could use Linq Sum
foreach (var array in accounts)
{
var sum = array.Sum();
if (sum > max)
max = sum;
}
Or you can use Linq Max and Sum
var max = accounts.Max(x => x.Sum());
Additional Resources
Enumerable.Max Method
Returns the maximum value in a sequence of values.
Enumerable.Sum Method
Computes the sum of a sequence of numeric values.

One easy to implement fix to your current attempt would be to just keep track of the maxAccountSum seen so far:
using System;
class MainClass
{
public static void Main (string[] args)
{
int[][] accounts = new int[3][];
accounts[0] = new int[] { 1, 2, 3 };
accounts[1] = new int[] { 2, 3, 4 };
accounts[2] = new int[] { 3, 4, 5 };
var maxAccountSum = Int32.MinValue; // To account for if the accounts have negative balances? Like they were all overdrafted or something.
for (var i = 0; i < accounts.Length; i++)
{
var accountSum = 0;
for (var j = 0; j < accounts[i].Length; j++)
{
accountSum += accounts[i][j];
}
maxAccountSum = Math.Max (maxAccountSum, accountSum);
}
Console.WriteLine ("The highest sum in an account is {0}.", maxAccountSum);
}
}
Time-Space Analysis:
O(mn) time, where m is the number of accounts and n is the max number of values in an individual account.
O(1) space, since we are only keeping track of a couple extra variables.
Output:
The highest sum in an account is 12.

Related

Minimum element of each column in array of arrays

An array of arrays is given. It is necessary to find the minimum element in each column and write the data to a new array. I have done the following implementation, in accordance with the given conditions. But I am having a problem:expected minimum element in each column of the array are incorrect. Where am I making a mistake?
class Program
{
static int[][] Input()
{
Console.Write("n = ");
int n = int.Parse(Console.ReadLine());
int[][] a = new int[n][];
//int[] minA = new int[n];
for (int i = 0; i < n; ++i)
{
a[i] = new int[n];
for (int j = 0; j < n; ++j)
{
Console.Write("a[{0},{1}]= ", i, j);
a[i][j] = int.Parse(Console.ReadLine());
}
}
return a;
}
static void Print(int[] a)
{
foreach (double elem in a)
{
Console.Write("{0} ", elem);
}
}
static void Print2(int[][] a)
{
for (int i = 0; i < a.Length; ++i, Console.WriteLine())
for (int j = 0; j < a[i].Length; ++j)
Console.Write("{0,5} ", a[i][j]);
}
static int[] F(int[][] a)
{
int[] b = new int[a[1].Length];
for (int j = 0; j < a[1].Length; j++)
{
int tempmin = a[0][j];
for (int i = 0; i < a[0].Length; i++)
{
if (a[j][i] <= tempmin)
{
tempmin = a[j][i];
b[j] += tempmin;
}
}
}
return b;
}
static void Main()
{
int[][] myArray = Input();
Print2(myArray);
int[] b = new int[myArray.Length];
b = F(myArray);
Print(b);
}
}
I suggest looping over all lines, while tracking all min columns values:
using System.Linq; // for the final `ToArray()`
...
private static int[] MinColumns(int[][] data) {
if (null == data)
throw new ArgumentNullException(nameof(data));
// List of columns' mins; initially the list is empty
List<int> list = new List<int>();
// for each line (not column!) within jagged array...
foreach (int[] line in data) {
// let's just skip null lines (alternative is to throw exception)
if (null == line)
continue;
// each new line can update columns' max values.
// now we update each column
for (int c = 0; c < line.Length; ++c)
// if index c is too big, i.e.
// the line is too long and some columns appear first time...
if (c >= list.Count)
// ...we just add values of such columns as columns' min
for (int i = list.Count; i <= c; ++i)
list.Add(line[i]);
else
// otherwise we update min values: we compare known min and current value
list[c] = Math.Min(list[c], line[c]);
}
// finally, we convert list into array with ahelp of Linq
return list.ToArray();
}
Note, that here we ignore all holes, e.g. for
int[][] demo = new int[][] {
new int[] {1, 2, 3, 4},
new int[] {5, 6}, // <- hole: we don't have 3d and 4th columns here
new int[] {7, 0, 8},
};
the answer will be {Min(1, 5, 7), Min(2, 6, 0), Min(3, 8), Min (4)} = {1, 0, 3, 4}
Edit: Usage is quite direct; something like this (fiddle yourself)
static void Main()
{
// Get jagged array
int[][] myArray = Input();
// Print it
Print2(myArray);
// Get max for each column
int[] b = MinColumns(myArray);
// Print these maxes
Print(b);
}

How to find the longest sequence of equal elements in an array of integers?

I want to write a program that finds the longest sequence of equal elements in an array of integers. If several longest sequences exist, we should print the leftmost one. e.g. Input: 0 1 1 5 2 2 6 3 3
Output: 1 1
I know that my code doesn't work correctly, but I don't know how to fix it. I should solve the problem using only arrays because I don't know how to use lists.
int[] numbers = Console.ReadLine().Split().Select(int.Parse).ToArray();
for (int i = 0; i < numbers.Length; i++)
{
int[] currentSequenceOfEqualElements = new int[numbers.Length];
for (int j = i + 1; j < numbers.Length; j++)
{
if (numbers[i] == numbers[j])
{
if (currentSequenceOfEqualElements[0] == 0)
{
currentSequenceOfEqualElements[0] = numbers[i];
currentSequenceOfEqualElements[1] = numbers[i];
}
else
{
currentSequenceOfEqualElements[i + 2] = numbers[i];
}
}
else
{
break;
}
}
Console.WriteLine(string.Join(' ', currentSequenceOfEqualElements));
}
I will be very grateful if you can explain to me how to do it.
Here is the solution using the MoreLinq library (https://morelinq.github.io/) that mjwills suggested.
Once you get used to linq and morelinq methods the code is easier to understand than custom algo with nested loops and if.
var numbers = new int[]{ 0, 1, 1, 5, 2, 2, 6, 3, 3};
var result = numbers.GroupAdjacent(x => x)
.MaxBy(x => x.Count())
.FirstOrDefault();
foreach (var i in result)
{
Console.Write($"{i} ");
}
Here's a simple solution, using only loops and no linq. It should be nice and easy to understand.
int[] numbers = new[] { 0, 1, 1, 5, 2, 2, 6, 3, 3 };
// Some variables to keep track of the sequence we're currently looking
// at, and the longest sequence we've found so far. We're going to start
// the loop at the 2nd number, so we'll initialize these as if we've
// already processed the first number (which is 0, so we've seen the
// first number of a sequence of 0's).
// Number of numbers in the current sequence
int count = 1;
// Number which is part of the longest sequence so faar
int longestNum = numbers[0];
// Number of numbers in the longest sequence we've seen so far
int longestCount = 1;
for (int i = 1; i < numbers.Length; i++)
{
// We're starting a new sequence
if (numbers[i] != numbers[i-1])
{
count = 0;
}
count++;
// Have we just found a new longest sequence?
if (count > longestCount)
{
longestCount = count;
longestNum = numbers[i];
}
}
// longestNum = 1 and longestCount = 2 (because the longest sequence
// had 2 1's in it). Turn this into the string "1 1".
Console.WriteLine(
string.Join(" ", Enumerable.Repeat(longestNum, longestCount)));
// If you wanted to end up with an array containing [1, 1], then:
int[] result = new int[longestCount];
Array.Fill(result, longestNum);
I will illustrate a recursive answer for your question, below is the code, I kept some if-else statements that there is no need to have them, but at least the code shows the idea.
The code has a basic method that should be exposed as public and a private recursive method that does the heavy lifting. The longest sequence is the empty array(list)
var longSequenceEqualElem = new List<int>();
Later on the recursion, you pass all the elems of the array through all the recursion calls to keep querying the positions, the pos parameter indicates the position level of the recursion.
if (pos < elems.Length) //stop the recursion here, the position will fall out of the indexes of the array, just return what you have in sequence that should be the longest.
The following statement if (sequence.Contains(elems[pos])) means that you found the same number you were carrying on the sequence in the position pos, so you can add it to the sequence and call the recursion with the adjacent position(pos + 1)
If the element in position pos is not part of the sequence you had, then you need to call the recursion with a new sequence containing elems[pos] and later compare the result of that recursion call with the sequence you had to see which of them is the longest one.
Hope this helps
class Program
{
static void Main(string[] args)
{
var elemts = new int[] { 0, 1, 1, 5, 2, 2, 6, 3, 3 };
var result = LongestSequence(elemts);
foreach (var i in result)
{
Console.Write(i + "\t");
}
Console.ReadLine();
}
public static int[] LongestSequence(int[] elems)
{
var longSequenceEqualElem = new List<int>();
return LongestSequenceRec(elems, longSequenceEqualElem, 0);
}
private static int[] LongestSequenceRec(int[] elems, List<int> sequence, int pos)
{
if (pos < elems.Length)
{
if (sequence.Contains(elems[pos]))
{
sequence.Add(elems[pos]);
return LongestSequenceRec(elems, sequence, pos + 1);
}
else
{
var newSeq = LongestSequenceRec(elems, new List<int> { elems[pos] }, pos + 1);
return (newSeq.Length > sequence.Count) ? newSeq.ToArray() : sequence.ToArray();
}
}
return sequence.ToArray();
}
}
static void Main()
{
int[] array1 = new int[9] {0, 1, 1, 5, 2, 2, 6, 3, 3};
int[] array2 = new int[9] {0, 0, 0, 0, 0, 0, 0, 0, 0};
int max_count = 1;
int tempCount = 1;
int num = 0;
for (int i = 0; i < array1.Length - 1; i++)
{
if (array1[i] == array1[i + 1]) tempCount++;
else tempCount = 1;
if (tempCount > max_count)
{
max_count = tempCount;
num = array1[i];
}
}
for (int i = 0; i < max_count; i++) array2[i] = num;
for (int i = 0; i < max_count; i++) Console.Write(array2[i] + " ");
Console.ReadKey();
}

How to sort ascending only odd numbers in array?

I want to sort only odd numbers without moving even numbers. For example, if my input is:
[5, 3, 2, 8, 1, 4]
The expected result is:
[1, 3, 2, 8, 5, 4]
I am new to C# and I came across a challenge on the Internet that has me perplexed. I have tried for hours and I would like to learn this concept in
The challenge states:
You have an array of numbers. Your task is to sort ascending odd numbers but even numbers must be on their places. Zero isn't an odd number and you don't need to move it. If you have an empty array, you need to return it.
Here is my code so far, please take it easy on me I am in the beginning stages of programming.
public static int[] SortArray(int[] array)
{
var dict = new Dictionary<int, int>();
var dict2 = new Dictionary<int, int>();
for (int i = 0; i < array.Length; i++)
{
int j =0;
if (array[i] % 2 != 0)
{
dict.Add(array[i], i+1);
}
else
{
dict2.Add(array[i], i+1);
}
}
var result = dict.OrderBy(x => x.Key);
Dictionary<int, int> resultDic = result.Union(dict2)
.GroupBy(x => x.Key).ToDictionary(o => o.Key, o => o.Key);
}
public static void Main()
{
SortArray(new int[] { 5, 3, 2, 8, 1, 4});
}
Check this code. Explanations added as comments
public static int[] SortArray(int[] array)
{
//temp variable for holding larger value for switching
int temp = 0;
for (int i = 0; i < array.Length; i++)
{
//If the value is 'even' continue with outer loop
if(array[i] % 2 == 0)
continue;
//Inner loop to compare array values
for(int j = (i + 1); j < array.Length; j++)
{
//If this value is not even do comparison
if(array[j] % 2 != 0)
{
//If the left value is greater than the right value
//swap them
if(array[i] > array[j])
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
return array;
}
public static void Main()
{
SortArray(new int[] { 5, 3, 2, 8, 1, 4});
}
You can do this with linq by indexing the numbers before you start:
var nums = new[] { 5, 3, 2, 8, 1, 4 };
var indexedNums = nums.Select((num, idx) => new { num, idx }).ToList();
Then sorting these indexed numbers into evens and odds:
var evens = indexedNums.Where(x => x.num % 2 == 0);
var odds = indexedNums.Where(x => x.num % 2 == 1);
Sorting the odd (indexed) numbers by their value:
var sortedOdds = odds.OrderBy(x => x.num); //sort the odd numbers by their value
Zipping this sequence with the odds sequence (which is sorted by index), taking the number from sortedOdds and the index from odds
var reindexedOdds = sortedOdds.Zip(odds, (o1, o2) => new { o1.num, o2.idx });
...and throwing these reindexedOdds into a sequence with the indexed evens from above, sorting by index and then selecting out the number.
var endSequence = evens.Concat(reindexedOdds).OrderBy(x => x.idx).Select(x => x.num);
While the other solutions are formally correct, most of them are not efficient, being with O(n^2) time complexity.
Another (and more time efficient) approach should imply the use of two lists: the first will contain the indexes of odd numbers, and the second will store the sorted odd numbers.
public static int[] SortArray(int[] array)
{
var sortedOdds = new List<int>(array.Length);
var oddsIndexes = new List<int>(array.Length);
var newArray = new int[array.Length];
for(var i = 0; i < array.Length; i++) // O(n)
{
var value = array[i];
if(value % 2 == 1)
{
sortedOdds.Add(value);
oddsIndexes.Add(i);
} else
{
newArray[i] = value;
}
}
sortedOdds.Sort(); // average complexity O(n log n)
for(var j = 0; j < sortedOdds.Count; j++) // O(n)
{
var value = sortedOdds[j];
var index = oddsIndexes[j];
newArray[index] = value;
}
return newArray;
}
This will reduce the complexity to an average of O(n log n) time.

C# masking an array to exclude indexes as fast as in python

What I have:
//This data set contains columns (second index) having the same value in each row (first index)
double[][] dataSet = new double[][]
{
new double[] {1, 2, 3, 4},
new double[] {5, 6, 7, 4},
new double[] {8, 9, 10, 4},
};
What i want to get:
// This data set has no column where the value in each row is the same
double[][] reducedDataSet = new double[][]
{
new double[] {1, 2, 3},
new double[] {5, 6, 7},
new double[] {8, 9, 10},
};
In python this can be easily done by:
all_equal_value_indices = numpy.all(data_set == data_set[0, :], axis=0) // Finds the indices of all columns that have equal values in each row
reduced_data_set = data_set[:, ~all_equal_value_indices] // Takes all rows with only those columns where all_equal_value_indices is not 1
In C# I can get an array containing the indices that should be excluded relatively fast, but how can I use these indices as mask to get only those columns not contained in these indices?
What i tried:
var numberOfDeletedColumns = 0;
var reducedDataSet = dataSet;
foreach (var columnToDelete in columnsToDelete)
{
reducedDataSet = reducedDataSet.RemoveColumn(columnToDelete - numberOfDeletedColumns++);
}
RemoveColumn is an extension provided by Accord.Net and has the following code:
/// <summary>Returns a new matrix without one of its columns.</summary>
public static T[][] RemoveColumn<T>(this T[][] matrix, int index)
{
T[][] objArray = new T[matrix.Length][];
for (int index1 = 0; index1 < matrix.Length; ++index1)
{
objArray[index1] = new T[matrix[index1].Length - 1];
for (int index2 = 0; index2 < index; ++index2)
objArray[index1][index2] = matrix[index1][index2];
for (int index2 = index + 1; index2 < matrix[index1].Length; ++index2)
objArray[index1][index2 - 1] = matrix[index1][index2];
}
return objArray;
}
But this is much slower than the implementation in python. Could someone suggest a faster method to achieve a reduced data set?
Array.Copy helps it run about 2x faster on my computer.
static T[][] FastRemoveColumn<T>(T[][] matrix, int index)
{
T[][] objArray = new T[matrix.Length][];
for (int i = 0; i < matrix.Length; i++)
{
var line = matrix[i];
var reducedline = new T[line.Length - 1];
Array.Copy(line, 0, reducedline, 0, index);
Array.Copy(line, index + 1, reducedline, index, line.Length - index - 1);
objArray[i] = reducedline;
}
return objArray;
}
and I also tried multithread. It runs very slow:
static T[][] MultiThreadRemoveColumn<T>(T[][] matrix, int index)
{
T[][] objArray = new T[matrix.Length][];
Parallel.For(0, matrix.Length, i =>
{
var line = matrix[i];
var reducedline = new T[line.Length - 1];
Array.Copy(line, 0, reducedline, 0, index);
Array.Copy(line, index + 1, reducedline, index, line.Length - index - 1);
objArray[i] = reducedline;
});
return objArray;
}
Test:
// init
double[][] arr = new double[2000][];
for (int i = 0; i < arr.Length; i++)
arr[i] = new double[2000];
double v = 0;
for (int i = 0; i < arr.Length; i++)
{
for (int j = 0; j < arr[i].Length; j++)
{
arr[i][j] = v;
v++;
}
}
Stopwatch sw = Stopwatch.StartNew();
var reducedArr = RemoveColumn(arr, 200);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();
var reducedArr2 = FastRemoveColumn(arr, 200);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();
var reducedArr3 = MultiThreadRemoveColumn(arr, 200);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
// Check the result
for (int i = 0; i < reducedArr.Length; i++)
{
for (int j = 0; j < reducedArr[i].Length; j++)
{
if(reducedArr[i][j] != reducedArr2[i][j]) throw new Exception();
if(reducedArr[i][j] != reducedArr3[i][j]) throw new Exception();
}
}
Update
Solution to remove several columns:
public static T[][] DeleteColumns<T>(T[][] matrix, int[] columns)
{
if (matrix.Length == 0) return new T[0][];
bool[] delColumns = new bool[matrix[0].Length];
foreach (int col in columns) delColumns[col] = true;
List<int> remainCols = new List<int>();
for (int i = 0; i < delColumns.Length; i++)
{
if (!delColumns[i]) remainCols.Add(i);
}
var target = new T[matrix.Length][];
for (int rowIndex = 0; rowIndex < matrix.Length; rowIndex++)
{
T[] sourceRow = matrix[rowIndex];
T[] targetRow = new T[remainCols.Count];
for (int i = 0; i < remainCols.Count; i++)
{
targetRow[i] = sourceRow[remainCols[i]];
}
target[rowIndex] = targetRow;
}
return target;
}
Test on a 2000x2000 matrix. Comparing with Adam Brown's solution, testing removing all columns is absolutely unfair, but my solution is faster even if removing only one column.
Sometimes, components don't work nicely in aggregate. In this case, your remove column function is reallocating the entire matrix, so the operation is linear in the number of columns you want to remove (ouch). To fix this, remove all the columns in one pass.
class Program
{
static void Main(string[] args)
{
var matrix = new[]
{
new [] {1, 2, 3, 4, 5},
new [] {1, 2, 3, 4, 5},
new [] {1, 2, 3, 4, 5},
new [] {1, 2, 3, 4, 5},
};
var result = matrix.DeleteColums(new [] {0, 2, 4});
foreach (var row in result)
{
foreach (var column in row)
{
Console.Write(column);
Console.Write(" ");
}
Console.WriteLine();
}
Console.ReadKey();
}
}
static class MatrixHelper
{
public static T[][] DeleteColums<T>(this T[][] matrix, int[] columns)
{
var sorted = columns.Distinct().OrderBy(e => e).Concat(new [] { int.MaxValue }).ToArray();
var target = new T[matrix.Length][];
for (int row = 0; row < matrix.Length; row++)
{
var sourceRow = matrix[row];
var targetRow = new T[sourceRow.Length - columns.Length];
var sortedIndex = 0;
for (int i = 0; i < sourceRow.Length; i++)
{
if (i == sorted[sortedIndex])
{
sortedIndex++;
continue;
}
targetRow[i - sortedIndex] = sourceRow[i];
}
target[row] = targetRow;
}
return target;
}
}
If this isn't enough, then you'll need to think about whether you need to use arrays. For instance, you could have a data structure for your matrix that dynamically masks columns, instead of an array-of-arrays.
UPDATE:
Given that other solutions in this page have assumed that the matrix, despite being represented by a jagged array, has the same indices per row, I thought I would give another go at making a faster solution. Here are two solutions that beat all previous ones in this thread, under those assumptions, including a faster parallel one.
public static T[][] DeleteColumns<T>(this T[][] matrix, int[] columns)
{
if (matrix.Length == 0) return matrix;
//Previous code assumed matrix could be jagged - new code assumes all columns
//present and all rows same length
var rowLength = matrix[0].Length;
if (rowLength == 0) return matrix;
var sorted = columns.Distinct().ToArray();
var target = new T[matrix.Length][];
var remainingLength = rowLength - sorted.Length;
//Allocate the targets all in one go - to avoid doing allocation in parallel.
for (var row = 0; row < matrix.Length; row++)
{
target[row] = new T[remainingLength];
}
//Work out remaining columns (previous code assumed these could
//be different per row, this assumes all rows have the same
//contents.
var remaining = Enumerable.Range(0, rowLength).Except(sorted).ToArray();
for (int row = 0; row < matrix.Length; row++)
{
var sourceRow = matrix[row];
var targetRow = target[row];
for (int i = 0; i < targetRow.Length; i++)
{
targetRow[i] = sourceRow[remaining[i]];
}
}
return target;
}
And the faster parallel one (allocation for the parallel one is now about 90% of the total time):
public static T[][] DeleteColumnsParallel<T>(this T[][] matrix, int[] columns)
{
if (matrix.Length == 0) return matrix;
//Previous code assumed matrix could be jagged - new code assumes all columns
//present and all rows same length
var rowLength = matrix[0].Length;
if (rowLength == 0) return matrix;
var sorted = columns.Distinct().ToArray();
var target = new T[matrix.Length][];
var remainingLength = rowLength - sorted.Length;
//Allocate the targets all in one go - to avoid doing allocation in parallel.
for (var row = 0; row < matrix.Length; row++)
{
target[row] = new T[remainingLength];
}
//Work out remaining columns (previous code assumed these could
//be different per row, this assumes all rows have the same
//contents.
var remaining = Enumerable.Range(0, rowLength).Except(sorted).ToArray();
Parallel.For(0, matrix.Length, row =>
{
var sourceRow = matrix[row];
var targetRow = target[row];
for (int i = 0; i < targetRow.Length; i++)
{
targetRow[i] = sourceRow[remaining[i]];
}
});
return target;
}
Results for 10000x10000 matrix with half the columns randomly removed.
My previous attempt: 1300ms
Best previous attempt: 450ms
My new serial version: 390ms
My new parallel version: 310ms
Time just to allocate the result matrix (i.e. lower bound on best achievable time): 265ms
But, I think it's important to call out a far, far faster solution. At the moment, in the fastest parallel solution, 90% of the time is spent allocating memory. If, on the other hand, you were to make a Matrix class that had it's own indexer, you would be able to dynamically pretend that certain columns of the underlying data structure didn't exist. Depending on how you're using the matrices, versus how often you're masking rows or columns, this could be dramatically faster.

Check for missing number in sequence

I have an List<int> which contains 1,2,4,7,9 for example.
I have a range from 0 to 10.
Is there a way to determine what numbers are missing in that sequence?
I thought LINQ might provide an option but I can't see one
In the real world my List could contain 100,000 items so performance is key
var list = new List<int>(new[] { 1, 2, 4, 7, 9 });
var result = Enumerable.Range(0, 10).Except(list);
Turn the range you want to check into a HashSet:
public IEnumerable<int> FindMissing(IEnumerable<int> values)
{
HashSet<int> myRange = new HashSet<int>(Enumerable.Range(0,10));
myRange.ExceptWith(values);
return myRange;
}
Will return the values that aren't in values.
Using Unity i have tested two solutions on set of million integers. Looks like using Dictionary and two "for" loops gives better result than Enumerable.Except
FindMissing1 Total time: 0.1420 (Enumerable.Except)
FindMissing2 Total time: 0.0621 (Dictionary and two for loops)
public static class ArrayExtension
{
public static T[] FindMissing1<T>(T[] range, T[] values)
{
List<T> result = Enumerable.Except<T>(range, values).ToList<T>();
return result.ToArray<T>();
}
public static T[] FindMissing2<T>(T[] range, T[] values)
{
List<T> result = new List<T>();
Dictionary<T, T> hash = new Dictionary<T, T>(values.Length);
for (int i = 0; i < values.Length; i++)
hash.Add(values[i], values[i]);
for (int i = 0; i < range.Length; i++)
{
if (!hash.ContainsKey(range[i]))
result.Add(range[i]);
}
return result.ToArray<T>();
}
}
public class ArrayManipulationTest : MonoBehaviour
{
void Start()
{
int rangeLength = 1000000;
int[] range = Enumerable.Range(0, rangeLength).ToArray();
int[] values = new int[rangeLength / 5];
int[] missing;
float start;
float duration;
for (int i = 0; i < rangeLength / 5; i ++)
values[i] = i * 5;
start = Time.realtimeSinceStartup;
missing = ArrayExtension.FindMissing1<int>(range, values);
duration = Time.realtimeSinceStartup - start;
Debug.Log($"FindMissing1 Total time: {duration:0.0000}");
start = Time.realtimeSinceStartup;
missing = ArrayExtension.FindMissing2<int>(range, values);
duration = Time.realtimeSinceStartup - start;
Debug.Log($"FindMissing2 Total time: {duration:0.0000}");
}
}
List<int> selectedNumbers = new List<int>(){8, 5, 3, 12, 2};
int firstNumber = selectedNumbers.OrderBy(i => i).First();
int lastNumber = selectedNumbers.OrderBy(i => i).Last();
List<int> allNumbers = Enumerable.Range(firstNumber, lastNumber - firstNumber + 1).ToList();
List<int> missingNumbers = allNumbers.Except(selectedNumbers).ToList();
foreach (int i in missingNumbers)
{
Response.Write(i);
}
LINQ's Except method would be the most readable. Whether it performs adequately for you or not would be a matter for testing.
E.g.
range.Except(listOfValues);
Edit
Here's the program I used for my mini-benchmark, for others to plug away with:
static void Main()
{
var a = Enumerable.Range(0, 1000000);
var b = new List<int>();
for (int i = 0; i < 1000000; i += 10)
{
b.Add(i);
}
Stopwatch sw = new Stopwatch();
sw.Start();
var c = a.Except(b).ToList();
sw.Stop();
Console.WriteLine("Milliseconds {0}", sw.ElapsedMilliseconds );
sw.Reset();
Console.ReadLine();
}
An alternative method which works in general for any two IEnunumerable<T> where T :IComparable. If the IEnumerables are both sorted, this works in O(1) memory (i.e. there is no creating another ICollection and subtracting, etc.) and in O(n) time.
The use of IEnumerable<IComparable> and GetEnumerator makes this a little less readable, but far more general.
Implementation
/// <summary>
/// <para>For two sorted IEnumerable<T> (superset and subset),</para>
/// <para>returns the values in superset which are not in subset.</para>
/// </summary>
public static IEnumerable<T> CompareSortedEnumerables<T>(IEnumerable<T> superset, IEnumerable<T> subset)
where T : IComparable
{
IEnumerator<T> supersetEnumerator = superset.GetEnumerator();
IEnumerator<T> subsetEnumerator = subset.GetEnumerator();
bool itemsRemainingInSubset = subsetEnumerator.MoveNext();
// handle the case when the first item in subset is less than the first item in superset
T firstInSuperset = superset.First();
while ( itemsRemainingInSubset && supersetEnumerator.Current.CompareTo(subsetEnumerator.Current) >= 0 )
itemsRemainingInSubset = subsetEnumerator.MoveNext();
while ( supersetEnumerator.MoveNext() )
{
int comparison = supersetEnumerator.Current.CompareTo(subsetEnumerator.Current);
if ( !itemsRemainingInSubset || comparison < 0 )
{
yield return supersetEnumerator.Current;
}
else if ( comparison >= 0 )
{
while ( itemsRemainingInSubset && supersetEnumerator.Current.CompareTo(subsetEnumerator.Current) >= 0 )
itemsRemainingInSubset = subsetEnumerator.MoveNext();
}
}
}
Usage
var values = Enumerable.Range(0, 11);
var list = new List<int> { 1, 2, 4, 7, 9 };
var notIncluded = CompareSortedEnumerables(values, list);
If the range is predictable I suggest the following solution:
public static void Main()
{
//set up the expected range
var expectedRange = Enumerable.Range(0, 10);
//set up the current list
var currentList = new List<int> {1, 2, 4, 7, 9};
//get the missing items
var missingItems = expectedRange.Except(currentList);
//print the missing items
foreach (int missingItem in missingItems)
{
Console.WriteLine(missingItem);
}
Console.ReadLine();
}
Regards,
y00daa
This does not use LINQ but it works in linear time.
I assume that input list is sorted.
This takes O(list.Count).
private static IEnumerable<int> get_miss(List<int> list,int length)
{
var miss = new List<int>();
int i =0;
for ( i = 0; i < list.Count - 1; i++)
{
foreach (var item in
Enumerable.Range(list[i] + 1, list[i + 1] - list[i] - 1))
{
yield return item;
}
}
foreach (var item in Enumerable.Range(list[i]+1,length-list[i]))
{
yield return item;
}
}
This should take O(n) where n is length of full range.
static void Main()
{
List<int> identifiers = new List<int>() { 1, 2, 4, 7, 9 };
Stopwatch sw = new Stopwatch();
sw.Start();
List<int> miss = GetMiss(identifiers,150000);
sw.Stop();
Console.WriteLine("{0}",sw.ElapsedMilliseconds);
}
private static List<int> GetMiss(List<int> identifiers,int length)
{
List<int> miss = new List<int>();
int j = 0;
for (int i = 0; i < length; i++)
{
if (i < identifiers[j])
miss.Add(i);
else if (i == identifiers[j])
j++;
if (j == identifiers.Count)
{
miss.AddRange(Enumerable.Range(i + 1, length - i));
break;
}
}
return miss;
}
Ok, really, create a new list which parallels the initial list and run the method Except over it...
I have created a fully linq answer using the Aggregate method instead to find the missings:
var list = new List<int>(new[] { 1, 2, 4, 7, 9 }); // Assumes list is ordered at this point
list.Insert(0, 0); // No error checking, just put in the lowest and highest possibles.
list.Add(10); // For real world processing, put in check and if not represented then add it/them.
var missing = new List<int>(); // Hold any missing values found.
list.Aggregate ((seed, aggr) => // Seed is the previous #, aggr is the current number.
{
var diff = (aggr - seed) -1; // A difference between them indicates missing.
if (diff > 0) // Missing found...put in the missing range.
missing.AddRange(Enumerable.Range((aggr - diff), diff));
return aggr;
});
The missing list has this after the above code has been executed:
3, 5, 6, 8
for a List L a general solution (works in all programming languages) would be simply
L.Count()*(L.Count()+1)/2 - L.Sum();
which returns the expected sum of series minus the actual series.
for a List of size n the missing number is:
n(n+1)/2 - (sum of list numbers)
this method here returns the number of missing elements ,sort the set , add all elements from range 0 to range max , then remove the original elements , then you will have the missing set
int makeArrayConsecutive(int[] statues)
{
Array.Sort(statues);
HashSet<int> set = new HashSet<int>();
for(int i = statues[0]; i< statues[statues.Length -1]; i++)
{
set.Add(i);
}
for (int i = 0; i < statues.Length; i++)
{
set.Remove(statues[i]);
}
var x = set.Count;
return x;
// return set ; // use this if you need the actual elements + change the method return type
}
Create an array of num items
const int numItems = 1000;
bool found[numItems] = new bool[numItems];
List<int> list;
PopulateList(list);
list.ForEach( i => found[i] = true );
// now iterate found for the numbers found
for(int count = 0; i < numItems; ++numItems){
Console.WriteList("Item {0} is {1}", count, found[count] ? "there" : "not there");
}
This method does not use LINQ and works in general for any two IEnunumerable<T> where T :IComparable
public static IEnumerable<T> FindMissing<T>(IEnumerable<T> superset, IEnumerable<T> subset) where T : IComparable
{
bool include = true;
foreach (var i in superset)
{
foreach (var j in subset)
{
include = i.CompareTo(j) == 0;
if (include)
break;
}
if (!include)
yield return i;
}
}
int sum = 0,missingNumber;
int[] arr = { 1,2,3,4,5,6,7,8,9};
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}
Console.WriteLine("The sum from 1 to 10 is 55");
Console.WriteLine("Sum is :" +sum);
missingNumber = 55 - sum;
Console.WriteLine("Missing Number is :-"+missingNumber);
Console.ReadLine();

Categories