How can I get an array value from my dictionary? - c#

In my code, I created a dictionary where the value is an array on integers. What I need to do is take one of those values within the array and set that as a value somewhere else. How would I do that? For reference, the dictionary looks like this:
public IDictionary<string, int[]> Statistics { get; set; } = new Dictionary<string, int[]>()
{
{ "STR", new int[] { 0, 0, 0 } },
{ "DEX", new int[] { 0, 0, 0 } },
{ "CON", new int[] { 0, 0, 0 } },
{ "INT", new int[] { 0, 0, 0 } },
{ "WIS", new int[] { 0, 0, 0 } },
{ "CHA", new int[] { 0, 0, 0 } }
};
So, I want to take the second integer in the array of whichever key I need, and then assign that value somewhere else.

I was able to figure it out. So, in the case of, say the key "STR", I would need to do the following
int x = Statistics["STR"][1];

Related

Use a multidimensional array of strings to write to file

I'm trying to develop a simple EPOS system that records inventory and processes transactions. At the moment I want it to write the contents of my arrays (Product, Price, Size, Stock Level) to file using Streamwriter as well as a random date at the top but I haven't been able to crack it. My global variables declared for these arrays are below.
readonly static string[] Products = { "1989 Jersey", "1977 Jersey", "2001 Jersey", "1986 Jersey", "1990 Jersey", "2005 Jersey", "1992 Jersey", "1996 Jersey", "1985 Jersey", "1989 Jersey", "1991 Jersey", "1992 Jersey", "1986 Jersey"};
readonly static decimal[] Price = {26m, 24m, 21m, 25m, 19m, 22m, 23m, 18m, 16.50m, 17.50m, 14m, 20m, 17.50m};
readonly static string[] Sizes = {"Extra Small", "Small", "Medium", "Large", "Extra Large"};
readonly static int[,] StartingStock = {{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1 }};
I am currently trying to get my code to work. I am invoking the method above in a Form Load event and it only passes the contents at Index 0,0 to file.
private void WriteToFileOpeningStock()
{
string[] Productlist = { Products[0], Sizes[0] };
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
for (int index = 0; index < Productlist.Length; index++)
{
outputfile.WriteLine(Productlist[index]);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
I tried to write string[] Productlist = { Products[0-12], Sizes[0-4] }; to get it to pass all of the array contents but it throws an exception "Index was outside the bounds of the array". I am new to C# and programming so any help would be very much appreciated.
You are looping through ProductList:
string[] Productlist = { Products[0], Sizes[0] };
This only has the first index of the Product inside and the first index of Sizes inside. So there are only two values it will output.
You need to create two nested for loops, looping through both Products and Sizes
If you just looking to list the products you could do something like this
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
for (int index = 0; index < Products.Length; index++)
{
outputfile.WriteLine(Products[index]);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
In general I would Create a Class to hold your product. Something like
public class Product
{
public string ProductName { get; set; }
public List<string> Sizes { get; set; }
public decimal Price { get; set; }
}
then you can do something like this to convert to the new class
Productlist = new List<Product>();
for (int x = 0; x < Products.Length; x++)
{
Productlist.Add(new Product()
{
ProductName = Products[x],
Price = Price[x],
Sizes = Sizes.ToList()
});
}
WriteToFileOpeningStock();
Then you could make the following changes to list the products in a file
private void WriteToFileOpeningStock()
{
try
{
//enable StreamwWriter Object
StreamWriter outputfile;
// create file
outputfile = File.CreateText("ProductList.txt");
//writing array contents to file
foreach(Product product in Productlist)
{
outputfile.WriteLine(product.ProductName);
outputfile.WriteLine("");
}
outputfile.Close();
MessageBox.Show("Data Entered");
}
catch
{
MessageBox.Show("Error");
}
}

List grouping dynamically

I want to group a list that includes integer List<int>.
List<CNode> cNodes
and the CNode is
public class CNode
{
public List<int> Elements;
// ...
}
I can group the cNodes like that
var groups = cNodes.GroupBy(node => node.Elements[0]);
foreach (var group in groups )
{
// ...
}
but as you see the groupping is depends the first element, I want to group it by all elements
For example if node.Elements.Count == 5 expected grouping result should be the same as for:
var groups = cNodes.GroupBy(node => new
{
A = node.Elements[0],
B = node.Elements[1],
C = node.Elements[2],
D = node.Elements[3],
E = node.Elements[4]
});
I couldn't find the solution.
Thanks.
You can use something like node.Take(5) with a proper IEqualityComparer like this:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var cNodes = new List<CNode>
{
new CNode{Elements = new List<int>{ 0, 0, 1, 1, 1 } },
new CNode{Elements = new List<int>{ 0, 0, 0, 1, 1 } },
new CNode{Elements = new List<int>{ 0, 1, 1, 0 } },
new CNode{Elements = new List<int>{ 0, 1, 1, 0, 0 } },
new CNode{Elements = new List<int>{ 0, 0, 0, 0 } },
new CNode{Elements = new List<int>{ 0, 0, 0, 0 } }
};
Console.WriteLine("\tGroup by 2:");
foreach (var group in cNodes.GroupByElements(2))
Console.WriteLine($"{string.Join("\n", group)}\n");
Console.WriteLine("\tGroup by 3:");
foreach (var group in cNodes.GroupByElements(3))
Console.WriteLine($"{string.Join("\n", group)}\n");
Console.WriteLine("\tGroup by all:");
foreach (var group in cNodes.GroupByElements())
Console.WriteLine($"{string.Join("\n", group)}\n");
}
}
static class CNodeExtensions
{
public static IEnumerable<IGrouping<IEnumerable<int>, CNode>> GroupByElements(this IEnumerable<CNode> nodes) =>
nodes.GroupByElements(nodes.Min(node => node.Elements.Count));
public static IEnumerable<IGrouping<IEnumerable<int>, CNode>> GroupByElements(this IEnumerable<CNode> nodes, int count) =>
nodes.GroupBy(node => node.Elements.Take(count), new SequenceCompare());
private class SequenceCompare : IEqualityComparer<IEnumerable<int>>
{
public bool Equals(IEnumerable<int> x, IEnumerable<int> y) => x.SequenceEqual(y);
public int GetHashCode(IEnumerable<int> obj)
{
unchecked
{
var hash = 17;
foreach (var i in obj)
hash = hash * 23 + i.GetHashCode();
return hash;
}
}
}
}
internal class CNode
{
public List<int> Elements;
public override string ToString() => string.Join(", ", Elements);
}
}
Output is:
Group by 2:
0, 0, 1, 1, 1
0, 0, 0, 1, 1
0, 0, 0, 0
0, 0, 0, 0
0, 1, 1, 0
0, 1, 1, 0, 0
Group by 3:
0, 0, 1, 1, 1
0, 0, 0, 1, 1
0, 0, 0, 0
0, 0, 0, 0
0, 1, 1, 0
0, 1, 1, 0, 0
Group by all:
0, 0, 1, 1, 1
0, 0, 0, 1, 1
0, 1, 1, 0
0, 1, 1, 0, 0
0, 0, 0, 0
0, 0, 0, 0
You wrote:
I want to group it by all elements
The solution given by Alex will only group by a limited number of elements. You said you want to group it by all elements, even if you have a CNode with 100 elements. Besides: his solution also crashes if property Elements of one of the CNodes equals null.
So let's create a solution that meets your requirement.
The return value will be a sequence of groups, where every group has a Key, which is a sequence of CNodes. All elements in the group are all source CNodes that have a property Elements equal to the Key.
With equal you mean SequenceEqual. So Elements[0] == Key[0] and Elements[1] == Key[1], etc.
And of course, you want to decide when Elements[0] equals Key[0]: do you want to compare by reference (same object)? or are two CNodes equal if they have the same property values? Or do you want to specify a IEqualityComparer<CNode>, so that you can see they are equal if they have the same Name or Id?
// overload without IEqualityComparer, calls the overload with IEqualityComparer:
IEnumerable<IGrouping<IEnumerable<Cnode>, CNode>> GroupBy(
this IEnumerable<CNode> cNodes)
{
return GroupBy(cNodes, null);
}
// overload with IEqualityComparer; use default CNode comparer if paramer equals null
IEnumerable<IGrouping<IEnumerable<Cnode>, CNode>> GroupBy(
this IEnumerable<CNode> cNodes,
IEqualityComparer<CNode> cNodeComparer)
{
// TODO: check cNodes != null
if (cNodeComparer == null) cNodeComparer = EqualityComparer<CNode>.Default;
CNodeSequenceComparer nodeSequenceComparer = new CNodeSequenceComparer()
{
CNodeComparer = cNodeComparer,
}
return sequenceComparer.GroupBy(nodeSequenceComparer);
}
You've noticed I've transferred my problem to a new EqualityComparer: this compare takes two sequences of CNodes and declares them equal if they SequenceEqual, using the provided IEqualityComparer<CNode>:
class CNodeSequenceComparer : IEqualityComparer<IEnumerable<CNode>>
{
public IEqualityComparer<CNode> CNodeComparer {get; set;}
public bool Equals(IEnumerable<CNode> x, IEnumerable<CNode> y)
{
// returns true if same sequence, using CNodeComparer
// TODO: implement
}
}
One of the things we have to keep in mind, is that your property Elements might have a value null (after all, you didn't specify that this isn't the case)
public bool Equals(IEnumerable<CNode> x, IEnumerable<CNode> y)
{
if (x == null) return y == null; // true if both null
if (y == null) return false; // false because x not null
// optimizations: true if x and y are same object; false if different types
if (Object.ReferenceEquals(x, y) return true;
if (x.GetType() != y.GetType()) return false;
return x.SequenceEquals(y, this.CNodeComparer);
}

2D array passed into JsonResult doesn't give me 2d array in json

Hi I have the following 2d array in c#
int[,] data = new int[3, 2] { { 0, 1690 }, { 1, 1696 }, { 2, 1659 } };
return Json(data, JsonRequestBehavior.AllowGet);
Is there a reason why I get the following json
[0,1690,1,1696,2,1659] instead of [[0,1690],[1,1696],[2,1659]]
I need this because that's what flot expects.
int[,] data = new int[3, 2] { { 0, 1690 }, { 1, 1696 }, { 2, 1659 } };
return JsonConvert.SerializeObject(data);

Accord and Mulit-label Support Vector Machines

I'm working through the example in the docs for a multi-class support vector machine - http://accord-framework.net/docs/html/T_Accord_MachineLearning_VectorMachines_MultilabelSupportVectorMachine.htm
Though, I'm not getting a 0 error rate, and when I try to compute values, they do not give the output values they should. Is there something wrong with the example?
static void Main(string[] args)
{
// Sample input data
double[][] inputs =
{
new double[] { 0 },
new double[] { 1 },
new double[] { 2 },
new double[] { 3 },
};
// Outputs for each of the inputs
int[][] outputs =
{
new[] {1,-1,-1,-1},
new[] {-1,1,-1,-1},
new[] {-1,-1,1,-1},
new[] {-1,-1,-1,1},
};
// Create a new Linear kernel
IKernel kernel = new Linear();
// Create a new Multi-class Support Vector Machine with one input,
// using the linear kernel and for four disjoint classes.
var machine = new MultilabelSupportVectorMachine(1, kernel, 4);
// Create the Multi-label learning algorithm for the machine
var teacher = new MultilabelSupportVectorLearning(machine, inputs, outputs);
// Configure the learning algorithm to use SMO to train the
// underlying SVMs in each of the binary class subproblems.
teacher.Algorithm = (svm, classInputs, classOutputs, i, j) =>
new SequentialMinimalOptimization(svm, classInputs, classOutputs);
// Run the learning algorithm
double error = teacher.Run();
error = teacher.Run(); // 0.1875 error rate
var answer = machine.Compute(new double[] {2}); // gives -1,-1,-1,-1, instead of -1,-1,1,-1
Should the error rate be zero, and why does it seem that only an input of 0 gives the right output?
To answer the question, it is very likely that there was something wrong with that particular example. Most examples have been updated to reflect the new .Learn() API that was put in place last year.
Now you may see that the documentation page for Multi-label Support Vector Machine has also changed addresses due the new API and is now at
http://accord-framework.net/docs/html/T_Accord_MachineLearning_VectorMachines_MultilabelSupportVectorMachine_1.htm
And now it includes this example, among others:
// Let's say we have the following data to be classified
// into three possible classes. Those are the samples:
//
double[][] inputs =
{
// input output
new double[] { 0, 1, 1, 0 }, // 0
new double[] { 0, 1, 0, 0 }, // 0
new double[] { 0, 0, 1, 0 }, // 0
new double[] { 0, 1, 1, 0 }, // 0
new double[] { 0, 1, 0, 0 }, // 0
new double[] { 1, 0, 0, 0 }, // 1
new double[] { 1, 0, 0, 0 }, // 1
new double[] { 1, 0, 0, 1 }, // 1
new double[] { 0, 0, 0, 1 }, // 1
new double[] { 0, 0, 0, 1 }, // 1
new double[] { 1, 1, 1, 1 }, // 2
new double[] { 1, 0, 1, 1 }, // 2
new double[] { 1, 1, 0, 1 }, // 2
new double[] { 0, 1, 1, 1 }, // 2
new double[] { 1, 1, 1, 1 }, // 2
};
int[] outputs = // those are the class labels
{
0, 0, 0, 0, 0,
1, 1, 1, 1, 1,
2, 2, 2, 2, 2,
};
// Create the multi-class learning algorithm for the machine
var teacher = new MulticlassSupportVectorLearning<Gaussian>()
{
// Configure the learning algorithm to use SMO to train the
// underlying SVMs in each of the binary class subproblems.
Learner = (param) => new SequentialMinimalOptimization<Gaussian>()
{
// Estimate a suitable guess for the Gaussian kernel's parameters.
// This estimate can serve as a starting point for a grid search.
UseKernelEstimation = true
}
};
// Configure parallel execution options
teacher.ParallelOptions.MaxDegreeOfParallelism = 1;
// Learn a machine
var machine = teacher.Learn(inputs, outputs);
// Obtain class predictions for each sample
int[] predicted = machine.Decide(inputs);
// Get class scores for each sample
double[] scores = machine.Score(inputs);
// Compute classification error
double error = new ZeroOneLoss(outputs).Loss(predicted);

using linq query to find value that differs from previously found value

Say i have a class that contains these items publicly accessible via properties:
class MyClass
{
int switch1; //0 or 1
int switch2; //0 or 1
int switch3; //0 or 1
}
This class represents switch states, and each time a switch state changes, i would like to add it to my transition list
I have a large sorted list that contains instances of this class and would like to use a query to capture only the entries in my list where the switch state for any switch changes.
Is this possible using a linq query?
try this:
Assuming your class looks like:
public class State
{
public int Id { get; set; }
public int Switch1 { get; set; }
public int Switch2 { get; set; }
public int Switch3 { get; set; }
public override bool Equals(object obj)
{
var other = obj as State;
if (other != null)
{
return Switch1 == other.Switch1 &&
Switch2 == other.Switch2 &&
Switch3 == other.Switch3;
}
return false;
}
}
I just added an Equals() to compare flags and my Id field is purely to demonstrate which items changed.
We can then craft a LINQ query like:
State previous = null;
var transitions = list.Where(s =>
{
bool result = !s.Equals(previous);
previous = s;
return result;
})
.ToList();
Not elegant, but it works, if you had this data set:
var list = new List<State>
{
new State { Id = 0, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
new State { Id = 1, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
new State { Id = 2, Switch1 = 1, Switch2 = 0, Switch3 = 0 },
new State { Id = 3, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 4, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 5, Switch1 = 0, Switch2 = 1, Switch3 = 0 },
new State { Id = 6, Switch1 = 1, Switch2 = 1, Switch3 = 0 },
new State { Id = 7, Switch1 = 0, Switch2 = 0, Switch3 = 1 },
new State { Id = 8, Switch1 = 0, Switch2 = 0, Switch3 = 1 },
new State { Id = 9, Switch1 = 0, Switch2 = 0, Switch3 = 0 },
};
And ran the query, the list would contain your state transitions at items: 0, 2, 3, 6, 7, 9
I would do as follow:
class MyClass
{
int ID; //needs for recognize the message
int switch1; //0 or 1
int switch2; //0 or 1
int switch3; //0 or 1
public int Pattern
{
get { return switch1 + switch2 << 1 + switch3 << 2; }
}
}
Then it must be declared a dictionary with the previous-state messages:
Dictionary<int, int> _prevStates;
each cell has for key the ID, and for value the "Pattern" of the message.
At this point, let's suppose that the new incoming message stream is a list of MyClass:
IEnumerable<MyClass> incoming = ...
var changed = from msg in incoming
where _prevStates.ContainsKey(msg.ID) //what to do?
where _prevStates[msg.ID].Pattern != msg.Pattern
select msg;
Finally, you must update the dictionary with the changed patterns.
Cheers

Categories