How to process data in passed to function in a channel? - c#

I wrote a function that will split the array passed to it into other arrays, depending on the number 1 of the array. For example 3, 2, 1, 1, 8, 2, 2, 9, 9 will be turned into [2, 1, 1], [8], [9, 9].
static async Task Main(string[] args) {
List<int> list = new List<int>() { 1, 2, 2, 5, 6, 3, 9, 9, 9 };
var source1 = Try(list);
foreach (var x in source1)
{
x.ForEach(i => Console.Write("{0} ", i));
Console.WriteLine();
}
}
static List<List<int>> Try(List<int> data, int d = 0)
{
var myChannel = Channel.CreateUnbounded<int>();
List<List<int>> outList = new List<List<int>>();
for (int p = 0; p < data.Count;)
{
d = data[p++]; // Get the size of the array
d = (d <= 0) ? 0 : d; // If the size is not correct, then we correct
List<int> tempList = new List<int>(new int[d]); //creating a temp list
for (var i = 0; i < d && p < data.Count; i++, p++)
tempList[i] = data[p]; // Filling the array with data
outList.Add(tempList); // Result, Combining split arrays into one single sheet
}
return outList;
}
I want to rewrite the code above to use Сhannel. That is, the input of the function receives a Сhannel with a sequence of numbers. The function processes them and returns the separated arrays in turn.
But how can I do it using Channel?
And I wanted to try to read the size of the transmitted Сhannel, but it's not possible, as well as iterate over the elements of the transmitted Сhannel. I wanted to read them, then assign them to the List, process them and return the separated arrays one by one.
List<int> list = new List<int>() { 1, 2, 2, 5, 6, 3, 9, 9, 9 };
var myChannel = Channel.CreateUnbounded<int>() ;
_ = Task.Factory.StartNew(async () =>
{
foreach (var j in list)
{
await myChannel.Writer.WriteAsync(j);
await Task.Delay(500);
}
});
await foreach (var item in FetchItems2(myChannel))
{
Console.WriteLine($"{item}");
}
static async IAsyncEnumerable<int[]> FetchItems2(Channel<int> data, int d = 0)
{
List<int> innerList = new List<int>();
/*broken code taken from a past solution without using channels
var item = await data.Reader.ReadAsync();
for (int p = 0; p < data.Count;)
{
d = data[p++]; // Get the size of the array
d = (d <= 0) ? 0 : d; // If the size is not correct, then we correct
int[] arr = new int[d]; // Create an array
for (var i = 0; i < d && p < data.Count; i++, p++)
arr[i] = data[p]; // Filling the array with data
*/
yield return arr; // returning split arrays
}
}

Find a solution:
1 function was finalized and await was added to it when passing through all elements
static async Task Main(string[] args)
{
List<int> list = new List<int>() { 1, 2, 2, 5, 6, 3, 9, 9, 9 };
var myChannel = Channel.CreateUnbounded<int>() ;
_ = Task.Factory.StartNew(async () =>
{
foreach (var j in list)
{
await myChannel.Writer.WriteAsync(j);
await Task.Delay(100); // just to see
}
}); // data in channel
Console.WriteLine($"Start");
await foreach (var item in FetchItems2(myChannel, list.Count))
{
//Console.WriteLine($"{item}");
foreach(var x in item)
{
Console.Write($"{x} ");
}
Console.WriteLine();
}
Console.WriteLine($"End");
}
static async IAsyncEnumerable<int[]> FetchItems2(Channel<int> data, int size, int d = 0)
{
List<int> innerList = new List<int>();
for(int i = 0; i < size; i++)
{
innerList.Add(await data.Reader.ReadAsync());
}
for (int p = 0; p < innerList.Count;)
{
d = innerList[p++]; // Get the size of the array
d = (d <= 0) ? 0 : d; // If the size is not correct, then we correct
int[] arr = new int[d]; // Create an array
// create new list
for (var i = 0; i < d && p < innerList.Count; i++, p++)
arr[i] = innerList[p]; // Filling the array with data
await Task.Delay(750);
yield return arr; // Result
}
}
The code is almost the same. In another way, data is written from the channel to the List.
The array is read correctly, then outputs the data line by line via yield

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);
}

Finding the sum of each array in a jagged array 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.

Set operations (complement and difference) [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
How can I make set complement and set difference in C# without using any collections and Linq?
We have two arrays:
int [] arr1 = new int { 1, 2, 3, 4};
int[] arr2 = new int {3,4,5,6,7,8};
Complement must be: arr3 {5,6,7,8} and the difference must be: arr4 {1,2}.
I've tried adding one set to another and then finding duplicates, but couldn't make it.
int numDups = 0, prevIndex = 0;
for (int i = 0; i < array.Length; i++)
{
bool foundDup = false;
for (int j = 0; j < i; j++)
{
if (array[i] == array[j])
{
foundDup = true;
numDups++; // Increment means Count for Duplicate found in array.
break;
}
}
if (foundDup == false)
{
array[prevIndex] = array[i];
prevIndex++;
}
}
// Just Duplicate records replce by zero.
for (int k = 1; k <= numDups; k++)
{
array[array.Length - k] = '\0';
}
You can create two lists, one for complement and other for difference, iterate array A and check which are contained in B and which not and vice-versa, iterate B and check which ones exists in A.
UPDATE: removed lists, used only arrays and no LINQ.
int[] arr1 = new int[]{ 1,2,3,4 };
int[] arr2 = new int[]{ 3,4,5,6,7,8 };
//We allocate the max possible size for each array, just for sanity
int[] arr3 = new int[arr1.Length + arr2.Length];
int[] arr4 = new int[arr1.Length + arr2.Length];
int difIndex = 0;
int compIndex = 0;
//Compute difference
foreach(int i in arr1)
{
bool found = false;
foreach(int i2 in arr2)
{
if(i == i2)
{
found = true;
break;
}
}
if(!found)
arr4[difIndex++] = i;
}
//Compute complement
foreach(int i in arr2)
{
bool found = false;
foreach(int i2 in arr1)
{
if(i == i2)
{
found = true;
break;
}
}
if(!found)
arr3[compIndex++] = i;
}
//Remove unused items from array
Array.Resize(ref arr3, compIndex);
Array.Resize(ref arr4, difIndex);
Given that premise, we could create the function getComplement like so:
int[][] getComplement(int[] arr1, int[] arr2) {
int[] complement = {};
int[] difference = {};
for (int i = 0; i < arr1.Length; i++)
{
bool isDupe = false;
for (int j = 0; j < arr2.Length; j++) {
if (arr1[i] == arr2[j] && !isDupe) {
Array.Resize(ref complement, complement.Length + 1);
complement[complement.GetUpperBound(0)] = arr2[j];
isDupe = true;
}
}
if (!isDupe) {
Array.Resize(ref difference, difference.Length + 1);
difference[difference.GetUpperBound(0)] = arr1[i];
}
}
return new[] { complement, difference };
}
and then apply it upon our 2 existing arrays to get the desired results:
int [] arr1 = new int[] { 1, 2, 3, 4 };
int[] arr2 = new int[] { 3, 4, 5, 6, 7, 8 };
int[][] complementArr = getComplement(arr1, arr2);
int[][] differenceArr = getComplement(arr2, complementArr[0]);
int[] arr3 = differenceArr[1];
int[] arr4 = complementArr[1];
You can see a working demo here.
The difference between collections A and B are all elements in A that are not in B. The compliment between those collections are all elements in B that are not in A. These are mirror definitions, so you really only need to write a method for difference and then have the compliment method call the difference method with the input parameters reversed.
(Well, strictly speaking, the compliment is all elements anywhere that are not in A, but that distinction is irrelevant here.)
// Get an array of all elements in b that are not in a
// This is identical to calling GetDifference with the inputs reversed so lets just do that
int[] GetCompliment(int[] a, int[] b) { return GetDifference(b, a); }
// Get an array of all elements in a that are not in b
int[] GetDifference(int[] a, int[] b)
{
// Create the buffer array at the worst-case length which is the length
// of a (where none of the elements in a are in b)
int[] c = new int[a.Length];
// Track how many elements we are actually ending up with
int length = 0;
// Loop through every element in a
foreach (var ax in a)
{
bool found = false;
// Loop through every element in b to see if it exists in a
foreach (var bx in b)
{
if (ax == bx)
{
// If the element was found in b, there's no reason to keep looping
found = true;
break;
}
}
// Only save the element if it was not found in b
if (!found)
{
c[length] = ax;
length++;
}
}
// Create the result array using the length of actual elements found
int[] result = new int[length];
// Copy the relevant slice of the buffer array into the result array
Array.Copy(c, result, length);
// Return the result array
return result;
}
Usage:
int[] a = { 1, 2, 3, 4 };
int[] b = { 3, 4, 5, 6, 7, 8 };
int[] c = GetDifference(a, b);
foreach(var cx in c)
{
Console.Write(cx + ", ");
}
Console.WriteLine();
int[] d = GetCompliment(a, b);
foreach(var dx in d)
{
Console.Write(dx + ", ");
}
// Output:
// 1, 2,
// 5, 6, 7, 8
DotNetFiddle

I want to get the "Index array" from a multi-dimensional array

I create a multi-dimensional array as follows:
List<int> indexList = GetFromSomewher()
Results = Array.CreateInstance(typeof(System.Double),indexList.ToArray() );
foreach (DataRow row in table.Rows)
{
List<int> indexInstance = new List<int>();
for (int d = 0; d < DegreesOfFreedom; d++)
{
indexInstance.Add(DimDict[d][row.Field<double>(d)]);
}
Results.SetValue(row.Field<double>(DegreesOfFreedom), indexInstance.ToArray());
}
Then, once created I want to see the index array and the value. BUT this only gives me the "value". I can see the index array in debug - but can't access it.
foreach (var res in Results)
{
Console.WriteLine("");
}
Sounds like a job for the humble for loop!
static void Main(string[] args)
{
int[][] test = new int[][] { new int[] { 1, 2, 3 }, new int[] { 4, 5, 6 }, new int[] { 7, 8, 9 } };
for(int i = 0; i < test.Length; i++)
{
for (int j = 0; j < test[i].Length; j++)
{
Console.WriteLine($"Index: [{i},{j}]: {test[i][j]}");
}
}
}

Algorithm for finding a group of numbers in a list that equal a target

So here is what I'm trying to do. I have a list of integers:
List<int> myList = new List<int>() {5,7,12,8,7};
And I also got a target:
int target = 20;
What I'm trying to do is find a way to create a new list of integer that when added together equal my target. So if my target is 20, I need a list like this:
{ 12, 8 }
If my target is 26, then I'll have this:
{ 7, 12, 7 }
Each number can only be used one time (7 is used twice because its in the list twice). If there is no solution, it should return an empty list. Anyone have any idea how I can do something like this?
That's a statistical problem. You want to find all possible combinations with a matching sum. I can recommend this project which is also worth reading:
http://www.codeproject.com/Articles/26050/Permutations-Combinations-and-Variations-using-C-G
Then it's easy and efficient:
List<int> myList = new List<int>() { 5, 7, 12, 8, 7 };
var allMatchingCombos = new List<IList<int>>();
for (int lowerIndex = 1; lowerIndex < myList.Count; lowerIndex++)
{
IEnumerable<IList<int>> matchingCombos = new Combinations<int>(myList, lowerIndex, GenerateOption.WithoutRepetition)
.Where(c => c.Sum() == 20);
allMatchingCombos.AddRange(matchingCombos);
}
foreach(var matchingCombo in allMatchingCombos)
Console.WriteLine(string.Join(",", matchingCombo));
Output:
12,8
5,7,8
5,8,7
Using recursion. Note that this solution will favor solutions that can be acquired by using the first items from the list. So for a target of 20, you won’t get 12+8 as the solution but 5+7+8.
List<int> findSum(List<int> numbers, int target, int index = 0)
{
// loop through all numbers starting from the index
for (var i = index; i < numbers.Count; i++)
{
int remainder = target - numbers[i];
// if the current number is too big for the target, skip
if (remainder < 0)
continue;
// if the current number is a solution, return a list with it
else if (remainder == 0)
return new List<int>() { numbers[i] };
else
{
// otherwise try to find a sum for the remainder later in the list
var s = findSum(numbers, remainder, i + 1);
// if no number was returned, we could’t find a solution, so skip
if (s.Count == 0)
continue;
// otherwise we found a solution, so add our current number to it
// and return the result
s.Insert(0, numbers[i]);
return s;
}
}
// if we end up here, we checked all the numbers in the list and
// found no solution
return new List<int>();
}
void Main()
{
List<int> myList = new List<int>() { 5, 7, 12, 8, 7 };
Console.WriteLine(findSum(myList, 12)); // 5, 7
Console.WriteLine(findSum(myList, 20)); // 5, 7, 8
Console.WriteLine(findSum(myList, 31)); // 5, 7, 12, 7
}
You can find all the solutions given below here: https://github.com/Mr-Zoidberg/Find-Possible-Combinations
1. Using recursion
static void Main(string[] args)
{
const int target = 20;
var numbers = new List<int> { 1, 2, 5, 8, 12, 14, 9 };
Console.WriteLine($"Number of Combinations: {SumCounter(numbers, target)}");
Console.ReadKey();
}
private static int SumCounter(IReadOnlyList<int> numbers, int target)
{
var result = 0;
RecursiveCounter(numbers, target, new List<int>(), ref result);
return result;
}
private static void RecursiveCounter(IReadOnlyList<int> numbers, int target, List<int> partial, ref int result)
{
var sum = partial.Sum();
if (sum == target)
{
result++;
Console.WriteLine(string.Join(" + ", partial.ToArray()) + " = " + target);
}
if (sum >= target) return;
for (var i = 0; i < numbers.Count; i++)
{
var remaining = new List<int>();
for (var j = i + 1; j < numbers.Count; j++) remaining.Add(numbers[j]);
var partRec = new List<int>(partial) { numbers[i] };
RecursiveCounter(remaining, target, partRec, ref result);
}
}
2. Get subsets using Linq
static void Main(string[] args)
{
const int target = 20;
var numbers = new int[] { 1, 2, 5, 8, 12, 14, 9 };
var matches = numbers.GetSubsets().Where(s => s.Sum() == target).ToArray();
foreach (var match in matches) Console.WriteLine(match.Select(m => m.ToString()).Aggregate((a, n) => $"{a} + {n}") + $" = {target}");
Console.WriteLine($"Number of Combinations: {matches.Length}");
Console.ReadKey();
}
}
public static class Extension
{
public static IEnumerable<IEnumerable<T>> GetSubsets<T>(this IEnumerable<T> collection)
{
if (!collection.Any()) return Enumerable.Repeat(Enumerable.Empty<T>(), 1);
var element = collection.Take(1);
var ignoreFirstSubsets = GetSubsets(collection.Skip(1));
var subsets = ignoreFirstSubsets.Select(set => element.Concat(set));
return subsets.Concat(ignoreFirstSubsets);
}
3. Another recursive method...
static void Main(string[] args)
{
const int target = 20;
var numbers = new [] { 1, 2, 5, 8, 12, 14, 9 };
var result = GetSubsets(numbers, target, "");
foreach (var subset in result) Console.WriteLine($"{subset} = {target}");
Console.WriteLine($"Number of Combinations: {result.Count()}");
Console.ReadLine();
}
public static IEnumerable<string> GetSubsets(int[] set, int sum, string values)
{
for (var i = 0; i < set.Length; i++)
{
var left = sum - set[i];
var vals = values != "" ? $"{set[i]} + {values}" : $"{set[i]}";
if (left == 0) yield return vals;
else
{
int[] possible = set.Take(i).Where(n => n <= sum).ToArray();
if (possible.Length <= 0) continue;
foreach (string s in GetSubsets(possible, left, vals)) yield return s;
}
}
}
4. Using binary search. Linear time.
static void Main(string[] args)
{
const int target = 20;
var numbers = new [] { 1, 2, 5, 8, 12, 14, 9 };
var subsets = GetSubsets(numbers, target);
foreach (var s in subsets) Console.WriteLine($"{s} = {target}");
Console.WriteLine($"Number of Combinations: {subsets.Count()}");
Console.ReadKey();
}
private static IEnumerable<string> GetSubsets(int[] array, int target)
{
Array.Sort((Array)array);
List<string> result = new List<string>();
for (int i = array.Length-1; i >= 0; i--)
{
var eq = $"{array[i]}";
var sum = array[i];
var toAdd = 0;
while (sum != target)
{
var mid = Array.BinarySearch(array, 0, sum <= target / 2 && sum != array[i] ? array.Length - 1 : i, target - sum);
mid = mid < 0 ? ~mid - 1 : mid;
if (mid == i || mid < 0 || toAdd == array[mid] ) break;
toAdd = array[mid];
sum += array[mid];
eq += $" + {array[mid]}";
if (sum == target) result.Add(eq);
}
}
return result;
}
This implementation of mine in C# will return all combinations(including repetitive use of same number) that equals a given number.
string r;
List<int> l = new List<int>();
void u(int w, int s, int K, int[] A) {
// If a unique combination is found
if (s == K) {
r += "(" + String.Join(" ", l) + ")";
return;
}
// For all other combinations
for (int i=w; i<A.Length; i++){
// Check if the sum exceeds K
int x = A[i];
if (s + x <= K){
l.Add(x);
u(i, s + x, K,A);
l.Remove(x);
}
}
}
string combinationSum(int[] a, int s) {
r = "";
u(0, 0, s, a.Distinct().OrderBy(x=>x).ToArray());
return r.Any() ? r : "Empty";
}
for a: [2, 3, 5, 9] and s = 9
the result will be :
"(2 2 2 3)(2 2 5)(3 3 3)(9)"

Categories