I am using the same code in my previous post but now I am trying to debug errors like
System.ArgumentNullException: 'Value cannot be null. (Parameter 'values')'
when I do
static void Main(string[] arg){
int[] numbers = new int[] { 2, 4 };
Console.WriteLine(String.Join(",", HowSum(7, numbers)));
}
How can I fix this when HowSum() returns a NULL?
Here is the original post for reference:
class HowSumSlow {
static int[] HowSum(int targetSum, int[] numbers)
{
int[] empty = new int[] { };
if (targetSum == 0) return empty;
if (targetSum < 0) return null;
foreach( var num in numbers){
var remainder = targetSum - num;
int[] remainderResult = HowSum(remainder, numbers);
if (remainderResult != null){
return remainderResult.Append(num).ToArray();
}
}
return null;
}
static void Main(string[] arg) {
int[] numbers = new int[] { 2, 3, 5 };
Console.WriteLine(String.Join(",", HowSum(8, numbers)));
}
}
How can I fix this when HowSum() returns a NULL?
You can use ?? to specify a fallback for the null array:
Console.WriteLine(String.Join(",", HowSum(7, numbers) ?? Array.Empty<int>()));
Now you are passing an empty int-array to String.Join if HowSum returns null.
just do a regular null check to find if the function returns null or not
if (HowSum(8 , numbers) != null) {
Console.WriteLine(String.Join(",", HowSum(8, numbers)));
} else {
Console.WriteLine("ITS NULLLLL");
}
Hope it helped. :)
In my previous answer (deleted since), I missed the recursion. So, you need the null return for the stop criterion.
Therefore, a negative targetSum value is a valid input while recursing but not as a start value.
So, what you could do, is to give it a "starter method" - like this:
// Your "HowSum" Method stays untouched!
static int[] StartHowSum(int targetSum, int[] numbers)
{
if (targetSum < 0)
{
throw new ArgumentOutOfRangeException (
nameof(targetSum), targetSum,
"Argument must be greater than or equal to 0."
);
}
if (targetSum == 0) return Array.Empty<int>();
// maybe also sanity-check `numbers`?
int[] result = HowSum(targetSum, numbers);
// Now that we checked input, is it possible to still get null OUTput?
return result ?? Array.Empty<int>();
}
static void Main(string[] arg) {
int[] numbers = new int[] { 2, 3, 5 };
Console.WriteLine(String.Join(",", StartHowSum(8, numbers)));
}
After taking into account what everyone said, I found that the simplest way was to just store the result and use a ?-operator. (Thank you everyone. I wanted to write that in each and every comment, but apparently I'm supposed to refrain from that.)
Here's the final code.
static int[] HowSum(int targetSum, int[] numbers)
{
int[] empty = new int[0];
if (targetSum == 0) return Array.Empty<int>();
if (targetSum < 0) return null;
foreach (var num in numbers)
{
var remainder = targetSum - num;
int[] remainderResult = HowSum(remainder, numbers);
if (remainderResult != null){
return remainderResult.Append(num).ToArray();
}
}
return null;
}
static void Main(string[] arg)
{
int[] numbers = new int[] { 2, 4 };
int[] result = HowSum(7, numbers);
Console.WriteLine(result == null ? "null" : String.Join(",", result));
}
}
Related
private static readonly List<long> KnownPrimes = new List<long>() { 2, 3, 5, 7};
static void Main(string[] args)
{
int numDivisors;
string input = "";
bool first = true;
while (!int.TryParse(input, out numDivisors))
{
if(!first) Console.WriteLine("You must enter a number with no other characters.");
Console.WriteLine("Find the least common multiple for numbers 1 through:");
input = Console.ReadLine();
first = false;
}
int index = -1;
//make sure that there are enough primes in the list
while (index == -1)
{
index = KnownPrimes.FindIndex(n => n > numDivisors);
if(index == -1) AppendNextPrime();
}
// prep the list with 0s
List<int> countPrimes = KnownPrimes.Select(n=>0) as List<int>;
When I debug that last line in Rider, it is showing:
Enumerable.Select() returned: Count = 5 countPrimes: null
From what I have read, LINQ shouldn't be able to return a null, and it doesn't appear to be, but somehow the variable is remaining null. I'm obviously missing something here, can anyone help me identify what I am doing wrong?
as operator will return null since the result of the Select ist no List<int> but an IEnumerable<int>. Replace it by ToList to make a List out of the IEnumerable:
List<int> countPrimes = KnownPrimes.Select(n=>0).ToList();
I am trying to generate a list of unique combinations/permutations of 3 allowable values for 20 different participants (each of the 20 participants can be assigned a value of either 1, 2, or 3).
An example of one combination would be an array on length 20 with all ones like such:
{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }
...and everything possible all the way up to
{ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }
where each value in the array can be 1, 2 or 3.
I am stuck on writing my GetAllCombinations() function and I looked at some articles on permutation, but everything I have found is just confusing me more. I am not even sure if permutation is what I need here
So far I have this:
public List<int[]> GetValidCombinations()
{
const int positions = 20;
int[] acceptableValues = new int[3] { 1, 2, 3 };
//DO I USE PERMUTATION HERE TO BUILD MY ARRAY LIST OF ALL POSSIBLE COMBINATIONS?
var allPossibleCombinations = GetAllCombinations(positions, acceptableValues);
List<int[]> validList = new List<int[]>();
foreach (var combination in allPossibleCombinations)
{
//omited for berevity but I would
//do some other validations here...
if (true)
{
validList.Add(combination);
}
}
return validList;
}
public List<int[]> GetAllCombinations(int positions, int[] acceptableValues)
{
//For now returning null because I
//don't know How the heck to do this...
return null;
}
I have looked at some examples of permutation and I tried to use something like this below, but it did not produce what I was looking for:
static IEnumerable<IEnumerable<T>>
GetPermutations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetPermutations(list, length - 1)
.SelectMany(t => list.Where(o => !t.Contains(o)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
public void Test()
{
const int k = 20;
var n = new[] { 1, 2, 3 };
var combinations = GetPermutations(n, k);
//DOES NOT WORK FOR WHAT I NEED
}
Running Test() worked with k was 3 or less but returned nothing if k was greater then 3.
Try this:
public static List<int[]> GetAllCombinations(int position, int[] acceptableVaues)
{
List<int[]> result = new List<int[]>();
int[] parent = new int[] { };
result = AddAPosition(parent, acceptableVaues);
while(position > 1)
{
var tmpResult = new List<int[]>();
foreach(var _parent in result)
{
tmpResult.AddRange(AddAPosition(_parent, acceptableVaues));
}
position--;
result = tmpResult;
}
return result;
}
public static List<int[]> AddAPosition(int[] parent, int[] acceptableValues)
{
List<int[]> result = new List<int[]>();
for (int i = 0; i< acceptableValues.Length; i++)
{
var anArray = new int[parent.Length + 1];
for (int j = 0; j< parent.Length; j++)
{
anArray[j] = parent[j];
}
anArray[parent.Length] = acceptableValues[i];
result.Add(anArray);
}
return result;
}
I want to use an object in catch block, which get me an exception in try block. I'm parsing some strings to int and need to catch the exception when it's impossible and see, what object was mistaken and in what line. Is that possible or not?
Some code dor example. Thanks.
static void Main(string[] args)
{
var result = Parse(new List<string>() { "3;5;7", "qwe;3;70" });
}
public static List<int[]> Parse(List<string> list)
{
try
{
return list.Select(str => str.Split(';'))
.Select(str => Tuple.Create(int.Parse(str[0]), int.Parse(str[1]), int.Parse(str[2])))
/// something happening
.ToList();
}
catch
{
//here in braces I want to know, which element was wrong
//"qwe" and whole line "qwe;3;70"
throw new FormatException($"Wrong line [{}]");
}
}
Declare the line and value item counters outside the try/catch block and increase them in the LINQ expression body:
public static List<int[]> Parse(List<string> list)
{
int line = 0;
int item = 0;
try
{
return list
.Select(str => {
line++;
item = 0;
return str
.Split(';')
.Select(i => { item++; return int.Parse(i); })
.ToArray();
})
.ToList();
}
catch
{
throw new FormatException($"Wrong line [{line}]; item [{item}]");
}
}
Demo: https://dotnetfiddle.net/uGtw7A
You need a reference to the object causing the exception. However as the instance lives only in the scope of the try-block you can´t access it any more (try and catch don´t share the same scope and thus can´t access the same variables) unless you´d declare the reference to that instance outside the try-bloc
As already mentioned in the comments you should use a normal foreach-loop to have access to the current line:
public static List<int[]> Parse(List<string> list)
{
var result = new List<int[]>();
foreach(var str in list)
{
try
{
var values = str.Split(';');
result.Add(Tuple.Create(
int.Parse(values[0]),
int.Parse(values[1]),
int.Parse(values[2]))
);
}
catch
{
//here in braces I want to know, which element was wrong
throw new FormatException($"Wrong line " + str");
}
}
return result;
}
However you can simply avoid all those exceptions by useing TryParse instead which returns false if parsing failed. So this boils down to something like this:
var values = str.Split(';');
int v0, v1, v2;
if(int.TryParse(values[0], out v0 &&
int.TryParse(values[1], out v1 &&
int.TryParse(values[2], out v2 &&))
result.Add(Tuple.Create(v0, v1, v2));
else
throw new FormatException($"Wrong line " + str");
I recommend manually looping through, splitting the data, checking you have enough elements, and then using TryParse on the numbers. I know this is a departure from using Linq, but it's the better way to do this with error checking:
public static List<int[]> Parse(List<string> list)
{
if (list == null)
{
throw new ArgumentNullException("list");
// you can use nameof(list) instead of "list" in newer versions of C#
}
List<int[]> result = new List<int[]>();
// Loop through the entries
for (int i = 0; i < list.Count; ++i)
{
// Be safe and check we don't have a null value
// I'm just skipping the 'bad' entries for now but
// you can throw an error, etc.
if (list[i] == null)
{
// do something about this? (an exception of your choosing, etc.)
continue;
}
// split the entry
string[] entryData = list[i].Split(';');
// check we have 3 items
if (entryData.Length != 3)
{
// do something about this?
continue;
}
// try to parse each item in turn
int a;
int b;
int c;
if (!int.TryParse(entryData[0], out a))
{
// do something about this?
continue;
}
if (!int.TryParse(entryData[1], out b))
{
// do something about this?
continue;
}
if (!int.TryParse(entryData[2], out c))
{
// do something about this?
continue;
}
// add to the results list
result.Add(new int[] { a, b, c });
}
// return the result
return result;
}
Scope is scope. Anything you define inside your try block and don't explicitly pass on is not going to be available in your catch block.
If you need this information you have to iterate manually over the list and try catch each attempt individually...
There are too many problems with your code, you're assuming that parameter list is not null and contains items that can be splitted in 3 strings, and that every string can be safely parsed to int.
If you not have all the above guaranties just check everything:
public static List<int[]> Parse(List<string> list)
{
if (list == null)
{
throw new ArgumentNullException(nameof(list));
}
var arrayOfStringArray = list
.Select(x => x.Split(';'))
.ToArray();
var resultList = new List<int[]>();
for (var i = 0; i < arrayOfStringArray.Length; i++)
{
var arrayOfString = arrayOfStringArray[i];
if (arrayOfString.Length != 3)
{
throw new InvalidOperationException("meaningfull message there!");
}
var arrayOfInt = new int[3];
for (var j = 0; j < arrayOfInt.Length; j++)
{
arrayOfInt[j] = TryParse(arrayOfString[j], i, j);
}
resultList.Add(arrayOfInt);
}
return resultList;
}
static int TryParse(string value, int line, int position)
{
int result;
if (!int.TryParse(value, out result))
{
throw new FormatException($"Item at position {line},{position} is invalid.");
}
return result;
}
I think that you just got a wrong approach here. Yes, using Tuple + Linq would be the laziest way to get your result but you can't generate custom errors as so.
Here is an example of how you can achieve something alike:
static void Main(string[] args)
{
var result = Parse(new List<string>() { "3;5;7", "qwe;3;70" });
}
public static List<Tuple<int, int, int>> Parse(List<string> list)
{
List<Tuple<int, int, int>> result = new List<Tuple<int, int, int>>();
int line = 0;
int errorCol = 0;
try
{
for (line = 0; line < list.Count; line++)
{
string[] curentLine = list[line].Split(';');
int result0, result1, result2;
errorCol = 1;
if (curentLine.Length > 0 && int.TryParse(curentLine[0], out result0))
errorCol = 2;
else
throw new Exception();
if (curentLine.Length > 1 && int.TryParse(curentLine[1], out result1))
errorCol = 3;
else
throw new Exception();
if (curentLine.Length > 2 && int.TryParse(curentLine[2], out result2))
result.Add(new Tuple<int, int, int>(result0, result1, result2));
else
throw new Exception();
}
return result;
}
catch
{
//here in braces I want to know, which element was wrong
throw new FormatException("Wrong line " + line + " col" + errorCol);
}
}
PS: Line and column start at 0 here.
Hi there is there a way to check specific integer array indexes for specific numbers in C#; for example what I would love to have worked would be:
if(si[6] || si[7] || si[8] == 3)
{
MessageBox.Show("3 detected")
}
else
{
continue();
{
Obviously this doesn't work. Is there a clean way to do this? Thank you for looking.
var indexes = new int[] {6, 7, 8};
if (indexes.Any(i => si[i] == 3))
{
MessageBox.Show("3 detected")
}
The simplest is to make three separate checks:
if (si[6] == 3 || si[7] == 3 || si[8] == 3)
You could do this a bit neater using a method with a params:
public static bool HasValue(int value, params int[] itemsToCheck)
{
bool valueDetected = false;
foreach(var item in itemsToCheck)
{
valueDetected |= item == value;
}
return valueDetected;
}
Then you could just call it like this:
if (HasValue(3, si[6], si[7], si[8]))
{
}
You can use Array.IndexOf function to find the index of the integer. If array has the integer then it will return the index else it will return -1.
Like this
int[] a = new int[] { 1, 2 };
int c = Array.IndexOf(a, 2);
With this array int[]{ 1, 2, 3, 4, 7, 8, 11, 15,16,17,18 };
How can i convert to this string array "1-4","7-8","11","15-18"
Suggestions ? Linq ?
var array = new int[] { 1, 2, 3, 4, 7, 8, 11, 15, 16, 17, 18 };
var result = string.Join(",", array
.Distinct()
.OrderBy(x => x)
.GroupAdjacentBy((x, y) => x + 1 == y)
.Select(g => new int[] { g.First(), g.Last() }.Distinct())
.Select(g => string.Join("-", g)));
with
public static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(
this IEnumerable<T> source, Func<T, T, bool> predicate)
{
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
var list = new List<T> { e.Current };
var pred = e.Current;
while (e.MoveNext())
{
if (predicate(pred, e.Current))
{
list.Add(e.Current);
}
else
{
yield return list;
list = new List<T> { e.Current };
}
pred = e.Current;
}
yield return list;
}
}
}
}
You don't need Linq; in fact, the easiest solution requires knowing about three positions in the array (your starting number, current number and the next number after the current), for which Enumerables are not well-suited.
Try this:
var start = 0;
var end = 0;
var write = false;
var builder = new StringBuilder();
for(var i=0; i<array.Length; i++)
{
//arranged this way to avoid ArrayOutOfBoundException
//if the next index doesn't exist or isn't one greater than the current,
//the current index is the end of our incremental range.
if(i+1 == array.Length || array[i+1] > array[i] + 1)
{
end = i;
write = true;
}
if(write)
{
if(end - start == 0) //one number
builder.Append(String.Format("{0}, ", array[start]);
else //multi-number range
builder.Append(String.Format("{0}-{1}, ", array[start], array[end]);
start = i+1;
end = i+1; //not really necessary but avoids any possible case of counting backwards
write = false;
}
}
You can rearrange this to reduce nesting of code, continue early in the loop logic, and remove a few vars; you'll gain a few millis of execution time. You'll also need to trim the last two characters (a trailing comma and space) off the end of the StringBuilder before getting the String out.
Here is a cut at it:
public static IEnumerable<string> ToRanges(this IEnumerable<int> values)
{
int? start = null, end = null;
foreach (var value in values.OrderBy(vv => vv))
{
if (!start.HasValue)
{
start = value;
}
else if (value == (end ?? start) + 1)
{
end = value;
}
else
{
yield return end.HasValue
? String.Format("{0}-{1}", start, end)
: String.Format("{0}", start);
start = value;
end = null;
}
}
if (start.HasValue)
{
yield return end.HasValue
? String.Format("{0}-{1}", start, end)
: String.Format("{0}", start);
}
}
What's the algorithm you want to implement? Figure out what you want to happen, then see if it could be made clearer with a LINQ translation. Here's something non-LINQ that could give you an idea.
int[] array = { 1, 2, 3, 4, 7, 8, 11, 15, 16, 17, 18};
List<string> ranges = new List<string>();
// code assumes array is not zero-length, is distinct, and is sorted.
// to do: handle scenario as appropriate if assumptions not valid
Action<int, int, List<string>> addToRanges = (first, last, list) =>
{
if (last == first)
list.Add(last.ToString());
else
list.Add(string.Format("{0}-{1}", first, last)); ;
};
int firstItem = array[0];
int lastItem = firstItem;
foreach (int item in array.Skip(1))
{
if (item > lastItem + 1)
{
addToRanges(firstItem, lastItem, ranges);
firstItem = lastItem = item;
}
else
{
lastItem = item;
}
}
addToRanges(firstItem, lastItem, ranges);
// return ranges or ranges.ToArray()