How to determine number of objects in array - c#

Once again I cannot find a solution myself (I have tried using Array.IndexOf(db, accnum) with a pos > -1 return boolean, but have reverted to this loop after I couldn't make it work).
So, I thought using db.Length would leave 'a' at the length of all the non-null elements in the array, however it seems to count the whole array, meaning that when the loop reaches a null element it causes an error. Is there a way to halt the loop count when it runs out of objects in the array?
void withdrawal()
{
int accnum;
double withdrawal;
//get and parse input details
accnum = int.Parse(tbNameEnt.Text);
withdrawal = double.Parse(tbBalaEnt.Text);
//check if account exists within existing objects
int a = db.Length;
for (int i = 0; i < a; i++)
{
if (db[i].GetAccNo() == accnum)
{
pos = i;
//deduct from balance
db[pos].SetBalance(db[pos].GetBalance() - withdrawal);
WithMess(); //success message
hide_form();
MakeWith2.Visible = false;
show_menu();
break;
}
else if ((db[i].GetAccNo() != accnum) && (i == db.Length - 1))
{
//account doesn't exist message
MessageBox.Show("Account does not exist");
}
}
}

If there are null items that pad the array.. break out of the loop when you reach one:
for (int i = 0; i < a; i++) {
if (db[i] == null)
break;
// the rest
Alternatively, use LINQ to filter the null items out:
foreach (var item in db.Where(x => x != null)) {
// loop here
}

Related

for loop skip list elements

i have a problem with the code i showed below.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace problem2
{
class Program
{
static void Main(string[] args)
{
int[] nums = Console.ReadLine().Split().Select(int.Parse).ToArray();
List<int> lst = nums.OfType<int>().ToList();
while (true)
{
string des = Console.ReadLine();
var output = Regex.Replace(des.Split(" ")[0], #"[^0-9a-zA-Z\ ]+", "");
if (output == "Add")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
lst.Add(value);
}
else if(output == "Remove")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
lst.Remove(value);
}else if(output == "Replace")
{
String result1 = System.Text.RegularExpressions.Regex.Match(des, #"\d+").Value;
var lastno = des.Split().Last();
List<int> lst2 = lst;
for (int i = 0; i < lst2.Count; i++)
{
if(lst[i] == int.Parse(result1))
{
lst[i] = int.Parse(lastno);
break;
}
}
lst = lst2;
}
else if(output == "Collapse")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
}
else
{
continue;
}
}
}else if (output == "Mort")
{
PrintValues(lst);
break;
}
}
}
public static void PrintValues(IEnumerable myList)
{
foreach (Object obj in myList)
Console.Write("{0} ", obj);
Console.WriteLine();
}
}
}
more precisely with this part of the code:
else if(output == "Collapse")
{
string val = Regex.Replace(des, "[^0-9]", "");
int value = int.Parse(val);
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
}
else
{
continue;
}
}
I tried with all sorts of options but the loop misses elements. as an example
entrance:
1 2 -1 0 -3 9 8 7 2
Collapse 8
Mort
output:
9 8
but the program gives me this output:
2 0 9 8 2
I tried to see what the problem is through the debugger and there I found that the loop misses elements
It should be,
for(int i = 0; i < lst.Count; i+=1)
{
int element = (int)lst[i];
if (element < value)
{
lst.RemoveAt(i);
i--;
}
else
{
continue;
}
}
As #David784 mentioned at the comments. When you remove element the from the itterating collection. You miss 1 element everytime after you delete the i item.
To elaborate on #Berkay's comment: You're changing a list as you're looping through it. If i is 2 and you remove that element, then the element that used to be at index 3 now becomes 2, and so forth. His method of decrementing i will work. Another way would be to use a linq .Where statement instead:
var newList = lst.Where(e=> e>=value).ToList();
You are modifying the collection you are iterating through. This moves elements to other indexes and invalidates the i you determine for following elements in the for header. Better loop backwards
for (int i = lst.Count - 1; i >= 0; i--) {
// Now you can safely remove (or add) elements without affecting
// the index of non yet processed elements.
}
You are still modifying the index of elements ahead, but you are moving backwards, now.
In Visual Studio, you can use the forr code snippet to create a reverse for-loop. Type
forr <tab> <tab>.
(and of course there is the for code snippet for a normal for loop. It will increment the index with i++ instead of i += 1.)
Also, if the list is very long and you are removing many elements, it is worth to think about performance. This approach could move around a great number of elements. Copying the elements you want to keep to a new list (initialized with an appropriate initial capacity), will be more performing in this case.

For-loop looping too often because it's not exiting properly (performance)

I currently have an array with a size of one million, and a method that parses new objects (each one with a key and value) or overwrites an object in case a new object has an already existing key. The thing is that the loop for the overwriting part is taking an extremely long time with an array this big because it is not exiting properly. For every element it parses it checks every index, so for a thousand elements to parse it would do a billion checks, which is obviously not desired behaviour.
private const int ARRAY_SIZE = 1000000;
private Paar[] pArr = new Paar[ARRAY_SIZE];
public void Put(string key, object value)
{
bool wasReplaced = false;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null && pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
wasReplaced = true;
}
}
if (wasReplaced == false)
{
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] == null)
{
pArr[i] = new Paar(key, value);
break;
}
else if (i >= pArr.Length)
{
throw new Exception("All slots full");
}
}
}
}
Edit: Note that I am using two loops to prevent the overwriting function from being able to parse an object with a duplicate key and new value into an empty index if there happens to be one before the duplicate key's index (for example if I set one or more random indexes to null).
string keyparse = "Key";
string valueparse = "Value";
Random rnd = new Random();
int wdh = 1000;
for (int i = 0; i < wdh; i++)
{
myMap.Put(keyparse + rnd.Next(1, 10000), valueparse + rnd.Next(1, 10000));
}
I tried to make the first part of the function add 1 to an int and break if the int reaches the number of elements parsed, but it does not seem to function properly, and neither does it affect the time taken by the function.
bool wasReplaced = false;
int count = 0;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null)
{
count += 1;
if (pArr[i] != null && pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
count += 1;
break;
}
else if (count == 1000)
{
break;
}
}
}
I don't really know why this wouldn't work or how else I could approach this, so I'm kind of stuck here... Any help is greatly appreciated!
Use a Dictionary - but you write it's for practice ...
In that case:
Speedup 1: (Assuming your key is unique!)
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null && pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
// wasReplaced = true;
return;
}
}
Speedup 2: When traversing in the first for-loop, save the first position of an empty space. Then you can use that instantly and only have to iterate the array once.
int empty = -1;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null )
{
if (pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
return;
}
}
else if( empty < 0 )
{
empty = i;
}
}
if( pArr >= 0 )
pArr[empty] = new Paar(key,value);
else // Array has been fully traversed without match and without empty space
throw new Exception("All slots full");
Speedup 3: You could keep track of the highest index used, so you can break the for-loop early.
Mind that these measures are only to speed up that part. I did not take into account many other considerations and possible techniques like hashing, thread-safety, etc.
There are several things may done here-
A minor improvement will be break your loop when you set wasReplaced = true
if (pArr[i] != null && pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
wasReplaced = true;
break;
}
But it is not a good solution
Another solution is you may use TPL (Task Parallel Library), to use multithread and multicore. There is a ParallelForEach() loop there.
Another solution is use Dictionary<string, string> to store your values, instead of using an array. Dictionary<> uses hash map, you will get a better performance.
If you still want to use your own implementation with array, then try to use hashing or heap algorithm to store your data. By using hashing or heap you can store/get/update data by O(log(n)) time complexity.
private List<Paar> pArr = new list<Paar>();
public void Put(string key, object value)
{
(from p in pArr
where p!= null && p.key!=key select p).ToList()
.ForEach(x => x.key== key, x.Value==value);
}
Try with Linq Query
As written in a comment, I suggest you to use Dictionary instead of Paar class, so you can do something like:
int ARRAY_SIZE= 100000;
Dictionary<string, object> pArr = new Dictionary<string, object>()
public void Put(string key, string object)
{
if(pArr.ContainsKey(key))
pArr[key] = value;
else
{
if(pArr.Count() >= ARRAY_SIZE)
throw new Exception("All slots full");
pArr.Add(key, value)
}
}
If you need to use Paar class, you can use the .ToDictionary(x => x.key, x => x.value) to work with it.
Given that you don't want to use a dictionary and there may be a match anywhere within the array, then the best you can do is search the whole array until you find a match, and capture the index of the first null item along the way (for an insertion point if a match is not found):
public static void Put(string key, object value)
{
int insertionIndex = -1;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null)
{
if (pArr[i].Key == key)
{
insertionIndex = i;
break;
}
}
else if (insertionIndex < 0)
{
insertionIndex = i;
}
}
if (insertionIndex < 0)
{
throw new Exception("All slots full");
}
else
{
pArr[insertionIndex] = new Paar(key, value);
}
}
I solved this by declaring an instance variable and a local variable which are then to be compared. I also fixed a logical error I made (now the second loop counts properly and the first loop doesn't count anymore if it overwrites something but instead returns).
The method still functions the same but now runs much more efficiently (took 7 seconds for 5kk parses compared to the previous 12 seconds for 1k parses!).
int _objectCount = 0;
public void Put(string key, object value)
{
int localCount = 0;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null)
{
localCount++;
if (pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
return;
}
}
if (localCount == _objectCount)
{
return;
}
}
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] == null)
{
pArr[i] = new Paar(key, value);
_objectCount++;
return;
}
else if (i >= pArr.Length)
{
throw new Exception("All slots full");
}
}
}

Comparing rapidly-changing string values to find frequent occurrences

My problem should be quite simple. I have a random generated string that changes multiple times per second. I want to return 1 if it appears x times consecutively.
My current code:
string s; //this is the generated string
int checker = 0;
string[] s_list = null;
if( cheaker == 0)
{
s_list[0] = s;
}
else if( cheaker == 1)
{
s_list[1] = s;
}
checker++;
if(s_list[0] == s_list[1]) return 1;
My problem is that I want to be able to change the amount of x times if appears and like this it will generate tons of code if the x is too big.
Do you think putting the current string into an array of string and compare them is the best way? There should be a better implementation.
To make the code generic for any given X, you should keep last X strings and check whether all they are equal, e.g.:
List<string> list = new List<string>();
if (list.Count >= X)
{
list.RemoveAt(0);
}
list.Add(newString);
return list.Count >= X && list.Any(s => s == list[0]);
I assume s_list is an array where you store all the generations of the string
string s;
string[] s_list;
// Your logic that would generate s and store it in s_list
// ...
// ...
int required_amount = 10; // whatever X amount you want
int current_sequence = 0;
// It's important to start at 1, and not 0,
// as you compare to the previous entry each time
for(int i = 1; i < s_list.Lenght; i++ )
{
if( s_list[i] == s_list[i-1] )
{
current_sequence++;
if(current_sequence >= required_amount)
{
return 1;
}
}
else
{
current_sequence = 0;
}
}

How do I detect when an element in an array is empty in C#? (When empty, element = 0)

I have an array of 5 integers, from 1 to 5. My assignment tells me I need to be able to detect whether atleast one element in the array is greater than zero. Only if ALL elements are empty, would I say that var isEmpty is true, and then return the value.
Code:
public static bool is_empty(int[] S, int n)
{
bool isEmpty = false;
for (int i = 0; i < n; i++)
{
if (S[i] != 0)
{
isEmpty = false;
}
else
{
isEmpty = true;
}
}
return isEmpty;
}
Your code doesn't work as it considers only the last element in the element in the loop. Try this: Return that the array is not empty once you found a non-empty element; otherwise, return that all elements are empty:
public static bool is_empty(int[] S, int n)
{
for (int i = 0; i < n; i++)
{
if (S[i] > 0) // negative values still count towards "being empty"
return false;
}
return true;
}
I'm not sure why you have the input parameter n. So I've removed it. And instead I've used a foreach loop to loop through every element in the array.
static bool IsEmpty(int[] S)
{
foreach (int x in S)
{
if (x != 0)
{
return false; //If any element is not zero just return false now
}
}
return true; //If we reach this far then the array isEmpty
}
I think by you don't need variables your teacher means you don't need the bool isEmpty, You can use LINQ like others are saying, but I doubt you know what that is yet.
Per your requirements, you can say that "if I encounter any non-zero value, I have all the information I need to return a response". If I check all values, and have not found any non-zeros, I also know how to respond then. So try:
for (int i = 0; i < n; i++)
{
if (S[i] != 0)
{
return false;
}
}
return true;
try this
bool isEmpty = false;
int count = 0;
for(int i=0;i<n;i++){
if(S[i] == 0){
count++;
}
}
isEmpty = (count==n);
Can you try
S.Any(x => x != 0);
This should give out true if any of the element in array is not equal to 0.
similarly, you can explore the option of All in case you need to check all the elements of an array.
S.All(x => x == 0);
so your code will be
public static bool is_empty(int[] S)
{
// return true if no element is 0
return !S.Any(x => x != 0);
// or use
return S.All(x => x == 0);
}
better still you don't need to create this method either, as you can directly call this statement from where you are calling this method (unless its called from multiple places).

Implementing an intersection merge of 2 array lists

For homework assignment we have to program a Intersection merge of 2 ArrayLists. I have done it using the following code
public void Intersection()
{
foreach (object obj1 in Developed)
{
Apps xApp = (Apps)obj1;
foreach (object obj2 in DPloyed)
{
Apps yApp = (Apps)obj2;
if (xApp.CompareName(yApp) == 0)
{
Inter.Add(yApp);
}
}
}
}
I would like to implement it rather using the while loop but the following code seems to keep missing elements in the list. It puts the first elements in the new intersection list but once the length of developed is increased from 1 element to 5 elements or more it does not add the new elements.
public void Intersection()
{
int i = 0;
int j = 0;
while (i < Developed.Count && j < DPloyed.Count)
{
Apps curA = (Apps)Developed[i];
Apps curB = (Apps)DPloyed[j];
if (curA.CompareName(curB) == 0)
{
Inter.Add(curA);
i++;
j++;
}
else if (curA.CompareName(curB) < 0)
{
i++;
}
else
j++;
}
}
Any help as to why the while loop does not work would be appreciated.
Thanks
Do this
while (i < Developed.Count || j < DPloyed.Count)
because may be both list may be having different Count.
and you need to put extra checks inside loop for indexes so that you don't get Index out of Range Exception.
Problem was not in the actual code for the merges. Problem found in my compare methods.

Categories