c# dictionary automatically break the for loop, - c#

Dictionary<double, Tuple<int,int>> dictionary = new Dictionary<double, Tuple<int,int>>();
for (int i = 0; i < x.Length; i++)
for (int j = i+1; j < x.Length; j++)
{
double weight = Math.Round(Math.Sqrt(Math.Pow((x[i] - x[j]), 2) + Math.Pow((y[i] - y[j]), 2)), 2);
string edges = i + "-" + j + "-" + weight;
listBox1.Items.Add(edges);
Tuple<int, int> tuple = new Tuple<int, int>(i, j);
dictionary.Add(weight, tuple);
}
var list = dictionary.Keys.ToList();
list.Sort();
foreach (var key in list)
{
string a = dictionary[key].Item1 + "--" + dictionary[key].Item2 + "--> " + key.ToString();
listBox2.Items.Add(a);
}
I am trying to store some values in dictionary. But in the for loop suddenly its break with uncomplete values. There is no error message.
When i comment out "dictionary.Add(weight, tuple);" listbox is showing all data i want.

If you try to Add to a Dictionary a key which was already added, it'll throw a DuplicateKeyException. This is highly likely since you're rounding your double, resulting in several which will become the same value.
Assuming by the use of a ListBox that you're using this in a UI event (Forms, WPF, or otherwise) I would say it probably is throwing an exception, but something else is catching that exception and moving on.
When adding to a dictionary, you should check if the key already exists, and handle appropriately.
If you want to override the value, keep in mind that this[TKey key] will not throw an exception when adding a new item. Thus
// dictionary.Add(weight, tuple);
dictionary[weight] = tuple;
If you want to skip past a value that's already present, check for ContainsKey
if(!dictionary.ContainsKey(weight))
dictionary.Add(weight, tuple);

Related

Sorted array using nested loops and substring method (C#)

I am trying to manually sort an array using string inputs that end with a number which I want to sort from highest to lowest.
For example I can start with this output:
,Name1: 1540
,Name2: 2660
,Name3: 80
,Name4: 380
And in the end it should look like this:
,Name2: 2660
,Name1: 1540
,Name4: 380
,Name3: 80
private string[] OrderHighToLow(string[] data)
{
string temp;
for (int i = 0; i < data.Length; i++)
{
for (int y = 0; y < i; y++)
{
if (int.Parse(data[y].Substring((data[y].IndexOf(':') + 2))) > int.Parse(data[i].Substring((data[i].IndexOf(':') + 2))))
{
temp = data[i];
data[i] = data[y];
data[y] = temp;
}
}
}
return data;
}
This is what I have tested. According to me, this should work, but the point is it doesn't, the application just crashes. So, if anyone here can figure out why that may be, I would be very thankful. Thanks in advance.
your comparison is worng
int.Parse(data[y].Substring((data[y].IndexOf(':') + 2)))
less than Not greater than
if (int.Parse(data[y].Substring((data[y].IndexOf(':') + 2))) < int.Parse(data[i].Substring((data[i].IndexOf(':') + 2))))
This should do the job with the Help of System.Linq:
private string[] OrderHighToLow(string[] data)
{
//create a temporary dictionary, which makes sorting easier
var tmpMap = new Dictionary<string, int>();
foreach (var item in data)
{
//split the string
var elems = item.Split(":");
//add string and int pair to the dictionary
tmpMap.Add(elems[0], int.Parse(elems[1]));
}
//sort Dictionary by value and use select to rebuild the string, then convert it back to an array
return tmpMap.OrderByDescending(x => x.Value).Select(x => $"{x.Key}: {x.Value}").ToArray();
}
Hope this helps.

Remove second occurrence of value from array C#

Instead of removing the first occurrence of a duplicated value, as my code currently does, how can I get it to delete the second occurrence instead?
namespace deletenumber
{
class Program
{
public static void Main(String[] args)
{
Random r = new Random();
int[] a = new int[10];
for (int i = 0; i < 10; i++)
a[i] = r.Next(1, 100);
for (int i = 0; i < 10; i++)
Console.WriteLine(" a [" + i + "] = " + a[i]);
Console.WriteLine();
Console.ReadLine();
Console.WriteLine("What number do you want to delete?");
int item = Convert.ToInt32(Console.ReadLine());
Console.WriteLine();
int index = Array.IndexOf(a, item);
a = a.Where((b, c) => c != index).ToArray();
Console.WriteLine(String.Join(", ", a));
Console.ReadLine();
}
}
}
I'm not sure why exactly you might want to delete only the second occurrence because there should be no matter which one of the duplicates is removed, correct?
Anyway, there are several ways of achieving what you want.
I will not directly write a solution here, but will propose the methods you can use in order to achieve what you want:
Array.LastIndexOf
Use the same IndexOf method again to find the second occurrence, by starting the search from the previous occurrence (myArray.IndexOf("string", last_indexof_index);)
Generally, consider using a HashSet<T> (official docs here) if you want to have a collection of unique elements.
You can also convert your existing collection to HashSet<int>:
int[] a = new int[10];
var set = new HashSet<int>(a);
You could convert your array to a List and then just remove the index before casting it back to an array:
var list = new List<int>(a);
list.RemoveAt(index);
a = list.ToArray();

Appending items to Dictionary with list inside [duplicate]

This question already has answers here:
.net dictionary and lookup add / update
(6 answers)
Closed 2 years ago.
How can I append items to Dictionary using list inside?
Here is my code:
Dictionary<string, List<double>> listVariables = new Dictionary<string, List<double>>();
And this is the way that I'm appending new values:
for (int x = 1; x <= 4; x++) {
listVariables["foo" + x].Add(1.1);
}
No errors found, but when I start my application, it crashs and I got this:
An unhandled exception of type 'System.Collections.Generic.KeyNotFoundException' occurred in mscorlib.dll
Additional information the given key was not present in the dictionary
I can make it works replaceing listVariables["foo" + x].Add(1.1); for listVariables["foo" + x] = new List<double> { 1.1 };
But this will always replace the first index value, I want append all data in a row of sequency
How can I solve that? Thank you very much.
You need to check if the key already exists, if not, you'll need to add it with an empty list:
for (int x = 1; x <= 4; x++)
{
var key = "foo" + x;
if (!listVariables.ContainsKey(key))
listVariables.Add(key, new List<double>());
listVariables[key].Add(1.1);
}
You need to check for the existence of the key first, adding a new list when necessary.
for (int x = 1; x <= 4; x++)
{
var key = "foo" + x;
if (!listVariables.ContainsKey(key))
listVariables[key] = new List<double>();
listVariables[key].Add(1.1);
}

adding element in a list throws ArgumentOutOfRangeException

My code throws this:
ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index error
When it finds an element in a list that have a count less that a specific number. any ideas on how to correct the code?
I've added debug.log code everywhere to determine exactly where the error happens, because no error is underlined by Visual Studio.
List<int> emptyRows = new List<int>();
for (int j = 0; j < gridPositions.Count; j++) // try to find if a row is still empty
{
Debug.Log("gridPositions[" + j + "].Count is " + gridPositions[j].Count);
Debug.Log("columns are" + columns);
if (gridPositions[j].Count == columns)
{
Debug.Log("trying to add to emptyrows");
emptyRows.Add(j);
Debug.Log("added to emptyrows and its count is " + emptyRows.Count);
}
else
{
Debug.Log("found an occupied row at row " + j);
//ERROR STRIKES HERE
}
Debug.Log("emptyRows is " + emptyRows[j]);
Debug.Log("emptyRows count is " + emptyRows.Count);
}
I expect the emptyRows to track and record all unoccupied rows, but when it fills an occupied row, it not proceeds whit the for loop and stops.
You are only adding to emptyRows if (gridPositions[j].Count == columns)
But you are accessing the emptyRows[j] on every value of j
So the emptyRows ends up having less items then the value of j is

Is there a data structure like a list with no duplicates that still allows indexing? [duplicate]

This question already has answers here:
HashSet with Index Access
(5 answers)
Closed 9 years ago.
I can't use a HashSet because I still need enumeration. If you're wondering why I need this, this is why:
private List<Point> sanitize(List<Point> crossPoints) {
HashSet<int> indexesToDelete = new HashSet<int>();
for (int i = 0; i < crossPoints.Count(); i++) {
if ((crossPoints[i].X - crossPoints[i + 1].X) <= 4) {
indexesToDelete.Add(i);
indexesToDelete.Add(i + 1);
}
}
for (int i = 0; i < crossPoints.Count(); i++) {
if ((crossPoints[i].Y - crossPoints[i + 1].Y) <= 4) {
indexesToDelete.Add(i);
indexesToDelete.Add(i + 1);
}
}
for (int i = 0; i < indexesToDelete.Count; i++) {
crossPoints.RemoveAt(indexesToDelete[i]);
}
return crossPoints;
}
This won't compile because of indexesToDelete[i]
If you want to iterate through the HashSet you can do:
foreach(int i in indexesToDelete)
{
...
But be careful when you delete items with RemoveAt! If you are not deleting the last entry, some of the other items will be moved and therefore get a new index.
One way to do this would be to sort the indexes and remove items from the highest to the lowest index.
var indexes = indexesToDelete.OrderByDescending(x => x).ToList();
foreach (int i in indexes)
{
crossPoints.RemoveAt(i);
}
You could also use SortedSet instead of HashSet.
SortedSet<int> indexesToDelete = new SortedSet<int>();
...
foreach(int i in indexesToDelete.Reverse())
{
crossPoints.RemoveAt(i);
}
There's an OrderedDictionary Class; however, it is not generic. The SortedDictionary<TKey, TValue> Class is generic. Note the difference between orderd and sorted. Ordered means that your insert order is kept intact. Sorted means that the insert order is ignored in favor of a sorting order.

Categories