I'm stuck trying to create array of arrays..
This is what i have for now, i would appreciate if someone could point me to right direction.
I have .txt file which has paths to images and each string has desired output separated with "|" like so:
":\\\img.png|1"
I'm trying to create array that has 2 columns and number of imagepaths as rows. Col 0 being a array of flattened rgb values of the image and col 1 being output as int.
I'm getting error from line Data[i][0] = Flat;
"Cannot implicitly convert type 'int[]' to 'int'"
It might be obvious to more experienced coders here but i cant wrap my head around this.
static int[][] CreateDataSet(string DatasetPath)
{
string[] Lines = File.ReadAllLines(DatasetPath);
int[][] Data = new int[Lines.GetUpperBound(0)][];
for (int i = 0; i <= Lines.GetUpperBound(0); i++)
{
Data[i] = new int[2];
string[] StringSplit = Lines[i].Split('|');
Data[i][1] = Convert.ToInt32(StringSplit[1]);
int[] Flat = FlattenArray(ImagetoArray(StringSplit[0]));
Data[i][0] = Flat;
}
return Data;
}
In an array, all elements must have same type (or at least must be assignable to a variable of the element's type).
You have two options.
The bad one: use array of objects.
object[][] data;
Now you can put everything in that array, but it will be slow (boxing of value types) and untyped (hard to use and to maintain).
Instead of a jagged array, use tuples.
(int[] FlattenedImage, int Output)[] data;
That looks a little bit weird, but it's actually very useful. It's strongly typed, it prevents boxing, and it uses nice and modern language features.
The big problem here is you have an int and an int[]. So the [0] index of Data must itself be an array, rather than merely an integer. And since the [0] and [1] subscripts are different types, you're really gonna need a completely different kind of data structure here.
Here's an example using Tuples:
static IEnumerable<(int, int[])> CreateDataSet(string DatasetPath)
{
var result = new List<(int, int[])> = new List<(int, int[])>();
foreach(string line in File.ReadLines(DatasetPath))
{
var lineData = line.Split('|');
yield return (int.Parse(linedata[1]), FlattenArray(ImageToArray(lineData[0])) );
}
}
or with linq:
static IEnumerable<(int, int[])> CreateDataSet(string DatasetPath)
{
return File.ReadLines(DatasetPath).Select(line => {
var data = line.Split('|');
return ( int.Parse(data[1]), FlattenArray(ImageToArray(data[0])) );
});
}
If you would create a class or a struct to containt the data it would look something like this:
class ImageData
{
public int[] FlatImate { get; }
public int Number { get; }
public ImageData(int[] flatImage, int number)
{
FlatImage = flatImage;
Number = number;
}
}
static ImageData[] CreateDataSet(string datasetPath)
{
string[] lines = File.ReadAllLines(datasetPath);
ImageData[] data = new ImageData[Lines.GetUpperBound(0)];
for (int i = 0; i <= lines.GetUpperBound(0); i++)
{
string[] stringSplit = lines[i].Split('|');
int number = Convert.ToInt32(stringSplit[1]);
int[] flat = FlattenArray(ImagetoArray(StringSplit[0]));
data[i] = new ImageData(flat, number);
}
return data;
}
Can a params[] variable hold a list, that has been passed as a parameter through a method in C#?
Wrote a method(AddIntegers) which requires multiple values to be taken as parameters. On the parameter list of a method, there is a params[] variable that is receiving the values thrown, when the method call is made in the Main method. But there is an exception that says "Cannot convert from system.collections.generic.List<> to an integer. Anyone knows why does that happen?
**** this is within the Main Method****
string Demostring = Console.ReadLine();
string[] tokens = Demostring.Split(',');
List<int> nums = new List<int>();
int oneNum;
foreach(string s in tokens)
{
if (Int32.TryParse(s, out oneNum))
nums.Add(oneNum);
}
int result1 = AddIntegers(nums);
**** this is the method to be called****
public static int AddIntegers(params int[] Restnum)
{
int result = 0;
foreach(int temp in Restnum)
{
result += temp;
}
return result;
}
No, a List<int> isn't an int[], so you can't use it as an argument for an int[] parameter. (The fact that it's a parameter array doesn't change that.)
Typically the solution to this is to have two overloads - one accepting a parameter array and one accepting an IEnumerable<T>:
public static int AddIntegers(params int[] numbers) =>
AddIntegers((IEnumerable<int>) numbers);
public static int AddIntegers(IEnumerable<int> numbers)
{
...
}
Note that for this specific example, you can just call the Sum extension method from LINQ to Objects, of course.
There are proposals for parameter arrays to be able to accept IReadOnlyList<T> rather than just T[], but that isn't in C# yet. (I'd love it, personally...)
This is because you are trying to insert a List inside an array parameter.
Instead of this:
int result1 = AddIntegers(nums);
You could do this:
int result1 = AddIntegers(nums.ToArray());
Or alternatively:
public static int AddIntegers(List<int> numbers)
{
return AddIntegers(numbers.ToArray());
}
public static int AddIntegers(params int[] Restnum)
{
int result = 0;
foreach(int temp in Restnum)
{
result += temp;
}
return result;
}
And then call it like you normally would.
private void button4_Click(object sender, EventArgs e)
{
const string demostring = "1,2,3,4,5,6";
var tokens = demostring.Split(',');
var nums = new List<int>();
foreach (var s in tokens)
if (int.TryParse(s, out var oneNum))
nums.Add(oneNum);
var result1 = AddIntegers(nums);
}
public static int AddIntegers(List<int> restnum)
{
var result = 0;
foreach (var temp in restnum)
result += temp;
return result;
}
im trying to use random number to to pull 30 strings out of a array of 58 strings and am using a bool array to check and make sure the same number is not called twice. the method and the program always crashes with a index out of range error. here is the method.
static string[] newlist(string[] s)
{
string[] newlist = {};
bool[] issearched = new bool[s.Length];
Random callorder = new Random();
for (int i = 0; i < 31; i++)
{
int number = callorder.Next(0, s.Length);
if (issearched[number] == false)
{
newlist[number] = s[number];
issearched[number] = true;//this is where it always crashes even though the ide says issearced has 58 elements and the random number is always smaller than that.
}
else
i--;
}
return newlist;
}
im sure its simple but i can't figure out why index of 8 is outside the range of the array of 58.
Your array newlist (what a confusing name) has no space to store anything.
This line
string[] newlist = {};
declares the array but without setting the space to store any element, so when you try to use the indexer on it you get the exception.
I suggest to use a different approach to find 30 strings from your passed array.
Using a List<string> and continue to add to this list until you have 30 elements in the list
static string[] newlist(string[] s)
{
List<string> selectedElements = new List<string>();
bool[] issearched = new bool[s.Length];
Random callorder = new Random();
while(selectedElements.Count < 30))
{
int number = callorder.Next(0, s.Length);
if (!issearched[number])
{
selectedElements.Add(s[number]);
issearched[number] = true;
}
}
return selectedElements.ToArray();
}
If you prefer to use arrays as from your method then a couple of fixing is required to your code
static string[] newlist(string[] s)
{
string[] newlist = new string[30];
bool[] issearched = new bool[s.Length];
Random callorder = new Random();
for (int i = 0; i < 30; i++)
{
int number = callorder.Next(0, s.Length);
if (issearched[number] == false)
{
newlist[i] = s[number];
issearched[number] = true;
}
else
i--;
}
return newlist;
}
The newlist array is declared to have space to store 30 elements
The for loops for 30 times (not 31 as from your current code)
The newlist should use as indexer the value of the variable i
I believe you're actually crashing here:
newlist[number] = s[number];
Replace
string[] newlist = {};
With
string[] newlist = new string[s.Length];
Your newlist size is 0 elements, nowhere are you allocating enough space for it.
Also your program will go into an infinite loop if the input size is less than 31 elements.
My brain is melting today and i cannot think how to do this simple bit of code. numberList is a string of numbers seperated by commas like '2, 34, 10' etc.. when i request a random number i need to check if the string has the number, if it does i want to keep requesting a random number until the random number is definitely not in the string. i cant think what kind of loop i would do to get this to work:
Random r = new Random();
public int RandomPos(int max) {
int i;
do {
i = r.Next(max) + 1;
}
while (!numberList.Contains(i.ToString()));
return i;
}
I'll just explain in text instead of code because I'm too lazy to write the code right now:
Use String.Split to break your list into an array, then (if you need to) parse it into integers.
Use Enumerable.Range(0, max).ToArray() to create a list of all the numbers you could select.
Subtract the first list from the second.
Randomly select an element from the final list.
This has the benefit that you don't need to keep picking things randomly and retrying in a potentially-infinite-but-not-really-in-practice loop.
edit: here's some code
string[] invalid = numberList.Split(", ");
var list = Enumerable.Range(0, max).Where(x => !invalid.Contains(x.ToString())).ToArray();
return list[r.Next(list.Count)];
Remove the !
do
{
i = r.Next(max) + 1;
}
while (numberList.Contains(i.ToString()));
Try it with this:
static string invalidNumbers = "0,1,2,3,4,5";
static Random random = new Random();
static int Randomize()
{
var randomInt = random.Next(0, 10);
if (!invalidNumbers.Split(',').Contains(randomInt.ToString()))
{
return randomInt;
}
else
{
return Randomize();
}
}
Providing a simple answer, you don't need Split(). This assumes no spaces between numbers, modify accordingly:
String modifiedNumberList = "," + numberList + ",";
do {
i = r.Next(max) + 1;
}
while (modifiedNumberList.Contains("," + i.ToString() + ","));
edit: I believe BrokenGlass is also right, you shouldn't have the "!", removed from my solution.
Maybe this is what you want? I used a regular while instead since I think they are easier to read, and the only thing I think you get wrong was the !.
public int RandomPos(int max) {
int i = r.Next(max);
var intList = numberList.Split(',').ToDictionary<string,int>((n) => int.Parse(n));
while(intList.Contains(i))
{
i = r.Next(max);
}
return i;
}
Assuming I need to split the numberList first to if they are in a string. That would make the third row look like:
A modification of #Dave's reply:
static string invalidNumbers = "0,1,2,3,4,5";
static Random random = new Random();
static int Randomize()
{
var randomInt = random.Next(0, 10);
var splitString = invalidNumbers.Split(',');
while (splitString.Contains(randomInt.ToString()))
{
randomInt = random.Next(0, 10);
}
return randomInt;
}
A couple ways to improve this:
1) Use a List<int> or something instead of a string to make your life easier
2) if max is small (say <1000 or something) generate the list of all possible values, order them randomly, and return numbers in sequence from that list.
As the number of "used" numbers approaches "max" you could end up in a very long loop before you get an unused number. For values of max over a couple hundred, this could actually be of consequence. This may or may not be a problem in your situation.
This code will cover all cases:
"1,2,3,4,5"...
"1, 2, 3,4,5"...
private static int GetRandomNumber(string existingNumbers, int max)
{
string[] existingNumbersArray = existingNumbers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<string> existingNumbersList = new List<string>();
foreach (string number in existingNumbersArray)
{
existingNumbersList.Add(number.Trim());
}
while (true)
{
Random rnd = new Random();
int value = rnd.Next(max);
if (!existingNumbersList.Contains(value.ToString()))
{
return value;
}
}
}
You can even take out this part:
string[] existingNumbersArray = existingNumbers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<string> existingNumbersList = new List<string>();
foreach (string number in existingNumbersArray)
{
existingNumbersList.Add(number.Trim());
}
so it will not be called each time you call GetRandomNumber function.
My addition to all the other answers..
const string invalidNumbers = "0,1,2,3,4,5";
Random random = new Random();
int value = 0;
List<int> tmpList = new List<int>();
foreach (var x in invalidNumbers.Split(','))
{
tmpList.Add(Int32.Parse(x));
}
do
{
value = random.Next(0, 10);
}
while (tmpList.Contains(value));
return value
Edit: missunderstood the question for the first post, anyway, here is a recursive solution.
It seems better to keep the numbers in a List, but if it is required to follow the format you asked, here it is:
const int MAX_ATTEMPTS = 10;
Random r = new Random();
string nlist = "2, 34, 10";
public int RandomPos(int max_val)
{
List<string> used = nlist.Replace(" ","").Split(',').ToList();
return _RandomPos(MAX_ATTEMPTS, max_val, used);
}
private int _RandomPos(int tl, int max, List<string> used)
{
if (tl <= 0)
throw new Exception("Could not generate random number. Too many tries.");
else
{
int rnum = r.Next(max);
if (!used.Contains(rnum.ToString()))
{
nlist += ", " + rnum.ToString();
return rnum;
}
else
return _RandomPos(tl - 1, max, used);
}
}
I realize there are a lot of entries, but I don't see any with some decent error checking. That being said, this will offer a few things:
Won't waste any effort when there's nothing to disqualify
Will only select from a range of possible choices
Will flag -1 if a number can't be chosen within the max range and not in the disqualifying list
So here goes:
public int RandomPos(int max)
{
// compile the list of numbers we need to disqualify
List<int> disqualified = numberList.Split(new[]{',',' '},StringSplitOptions.RemoveEmptyEntries).Select(n => int.Parse(n)).ToList();
// Nothing to check against, save the CPU cycles
if (disqualified.Count == 0)
return (new Random(DateTime.Now.Millisecond)).Next(max) + 1;
// make a list of everything that's possible for a choice
List<int> valid = Enumerable.Range(0, max).Where(r => !disqualified.Contains(r)).ToList();
// return either a valid result, or -1 if there are no valid results
return (valid.Count == 0 ? -1 : valid[(new Random(DateTime.Now.Millisecond)).Next() % valid.Count]);
}
.Split will do the work, the following code will work as well, just for fun (replace the line while (!numberList.Contains(i.ToString())); in your code instead of checking i.ToString() check ","+i.ToString()+"," PLUS the beginning and ending. You need to adjust it if you have a space after ","):
while (!numberList.StartsWith(i.ToString()+",")&&
!numberList.Contains(","+i.ToString()+",")&&
!numberList.EndsWith(","+i.ToString()));
// if numberList is large then use HashSet<int> rather than a plain int[] array
int[] nums = numberList.Split(new[] { ',', ' ' },
StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();
int i;
while (nums.Contains(i = r.Next(max) + 1));
return i;
(You should also add a check to ensure that you don't end up in an infinite loop if/when numberList contains all the possible values that might be produced by the rng.)
Hi I coded this OneAtRandom() extension method:
public static class GenericIListExtensions
{
public static T OneAtRandom<T>(this IList<T> list)
{
list.ThrowIfNull("list");
if (list.Count == 0)
throw new ArgumentException("OneAtRandom() cannot be called on 'list' with 0 elements");
int randomIdx = new Random().Next(list.Count);
return list[randomIdx];
}
}
Testing it using this unit test fails:
[Test]
public void ShouldNotAlwaysReturnTheSameValueIfOneAtRandomCalledOnListOfLengthTwo()
{
int SomeStatisticallyUnlikelyNumberOf = 100;
IList<string> list = new List<string>() { FirstString, SecondString };
bool firstStringFound = false;
bool secondStringFound = false;
SomeStatisticallyUnlikelyNumberOf.Times(() =>
{
string theString = list.OneAtRandom();
if (theString == FirstString) firstStringFound = true;
if (theString == SecondString) secondStringFound = true;
});
Assert.That(firstStringFound && secondStringFound);
}
It seems that int randomIdx = new Random().Next(list.Count);is generating the same number 100 times in a row, I think possibly because the seed is based on the time?
How can I get this to work properly?
Thanks :)
You shouldn't be calling new Random()for every iteration because it causes it to be reseeded and generate the same sequence of numbers again. Create one Random object at the start of your application and pass it into your function as a parameter.
public static class GenericIListExtensions
{
public static T OneAtRandom<T>(this IList<T> list, Random random)
{
list.ThrowIfNull("list");
if (list.Count == 0)
throw new ArgumentException("OneAtRandom() cannot be called on 'list' with 0 elements");
int randomIdx = random.Next(list.Count);
return list[randomIdx];
}
}
This also has the advantage of making your code more testable as you can pass in a Random that is seeded to a value of your choice so that your tests are repeatable.
No; it's generating the same number 100 times because you're not seeding the generator.
Move the "new Random()" to the constructor or a static var, and use the generated object.
You could use a seed based on the current time to create the instance of Random. A sample on MSDN uses the following code:
int randomInstancesToCreate = 4;
Random[] randomEngines = new Random[randomInstancesToCreate];
for (int ctr = 0; ctr < randomInstancesToCreate; ctr++)
{
randomEngines[ctr] = new Random(unchecked((int) (DateTime.Now.Ticks >> ctr)));
}