Issue passing <List> object to multidimensional array - c#

Issue trying to pass coordinates in to a multidimensional array. Errors thrown:
(1) at var newArray = item.To2dArray(); in GetInstructions() method:
List does not contain a definition for To2dArray and no extensible method To2dArray accepting a first argument of type ist
(2) at public partial class SiteMaster : MasterPage when the method public static Coords[,] To2dArray(this List<List<Coords>> list) is added
Extension method must be defined in non-generic static class
My list structure
public class Route
{
public string status_message { get; set; }
public string route_geometry { get; set; }
public int status { get; set; }
//route_instructions is what I'm interested in
public List<List<object>> route_instructions { get; set; }
}
public class Coords
{
public int Lat { get; set; }
public int Lon { get; set; }
public Coords(string a, string b)
{
this.Lat = Convert.ToInt32(a);
this.Lon = Convert.ToInt32(b);
}
}
List<Coords> Coordinates = new List<Coords>();
Code to deserialise JSON
private void GetInstructions()
{
string strurltest = String.Format("https://developers.onemap.sg/privateapi/routingsvc/route?start="+
startLat+","+ startLon +"&end="+ destinationLat +","+ destinationLon+"&"+
"routeType="+ transportType + "&token="+token);
WebRequest requestObjGet = WebRequest.Create(strurltest);
requestObjGet.Method = "GET";
HttpWebResponse responseObjGet = null;
responseObjGet = (HttpWebResponse)requestObjGet.GetResponse();
string strresulttest = null;
using (Stream stream = responseObjGet.GetResponseStream())
{
StreamReader sr = new StreamReader(stream);
strresulttest = sr.ReadToEnd();
sr.Close();
}
Route route = new JavaScriptSerializer().Deserialize<Route>(strresulttest);
route_geometry = route.route_geometry;
//display route instructions
foreach (var item in route.route_instructions)
{
var newArray = item.To2dArray();
System.Diagnostics.Debug.WriteLine(item[3]);
TextBox3.Text = TextBox3.Text + Environment.NewLine + item[9];
}
}
Code to convert list object to multidimensional array
public static Coords[,] To2dArray(this List<List<Coords>> list)
{
if (list.Count == 0 || list[0].Count == 0)
throw new ArgumentException("The list must have non-zero dimensions.");
var result = new Coords[list.Count, list[0].Count];
for (int i = 0; i < list.Count; i++)
{
for (int j = 0; j < list[i].Count; j++)
{
if (list[i].Count != list[0].Count)
throw new InvalidOperationException("The list cannot contain elements (lists) of different sizes.");
result[i, j] = list[i][j];
}
}
return result;
}
List object when printed is in this format: (when System.Diagnostics.Debug.WriteLine(item[3]); in GetInstructions()
1.315396,103.764419
1.314333,103.763455
1.312906,103.766496
1.312109,103.772234

You can only use a Method as Extension, if it is static and in an static class.
Your method To2dArray must be moved to an extra static class.
This is what the following message means:
Extension method must be defined in non-generic static class
The other problem is, that the signature of the method does not fit:
You are iterating through route.route_instructions so item is of type List<object> but your method needs List<List<Coords>>
foreach (var item in route.route_instructions)
{
var newArray = item.To2dArray();
///...

Related

sorting a generic list from within a generic container class

I need to sort a list by any one of its properties, but i dont know which of these properties it will specifically be sorted on. The Main method below.
static void Main(string[] args)
{
Things<Something> something = new Things<Something>();
something.Add(new Something
{ Thing = "Apartment", Price = 1500000 });
something.Add(new Something
{ Thing = "Bed", Price = 10000 });
something.Add(new Something
{ Thing = "Lamp", Price = 600 });
something.Add(new Something
{ Thing = "Car", Price = 5000000 });
Console.WriteLine("\n\tStuff sorted by description");
something = something.SelectionSort("Thing");
foreach (Something thing in something)
Console.WriteLine("\t" + thing);
Console.WriteLine("\n\tStock items sorted by value");
something = something.SelectionSort("Value");
foreach (Something thing in something)
Console.WriteLine("\t" + thing);
Console.Write("\n\tPress any key to exit ...");
Console.ReadKey();
}
I have a struct
public struct Something
{
public string Thing { get; set; }
public decimal Price { get; set; }
}
And a generic container class called things
public class Things<T> : IEnumerable<T>
{
private List<T> lstItems;
public int Count { get { return lstItems.Count; } }
public Things() { lstItems = new List<T>(); }
public Things(List<T> items_) { lstItems = new List<T>(items_); }
public void Add(T item)
{
lstItems.Add(item);
}
public T this[int i]
{
get { return lstItems[i]; }
set { lstItems[i] = value; }
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new System.NotImplementedException();
}
public IEnumerator<T> GetEnumerator()
{
foreach (T item in lstItems)
yield return item;
}
}
An extensions class extends the generic container class
public static class ExtensionsClass
{
private static string SortFiield { get; set; }
private static object GetProperty<T>(T thing, string nameofProp)
{
return thing.GetType().GetProperty(nameofProp).GetValue(thing, null);
}
private static int Compare<T>(T x, T y)
{
IComparable propX = (IComparable)GetProperty(x, SortFiield);
IComparable propY = (IComparable)GetProperty(y, SortFiield);
return propX.CompareTo(propY);
}
public static Things<T> SelectionSort<T>(this Things<T> things, string SORTFIELD)
{
List<T> lsstt = new List<T>(things);
int iIndex;
T temporary;
SortFiield = SORTFIELD;
for (int i = 0; i < lsstt.Count - 1; i++)
{
iIndex = i;
for (int j = i + 1; j < lsstt.Count; j++)
{
string first = GetProperty(lsstt[j], SortFiield).ToString();
string second = GetProperty(lsstt[iIndex], SortFiield).ToString();
if (Compare(first, second) < 0)
iIndex = j;
}
temporary = lsstt[i];
lsstt[i] = lsstt[iIndex];
lsstt[iIndex] = temporary;
}
return new Things<T>(lsstt);
}
}
The problem i am encountering is that get property in the extension class returns null, but i know that the object i am trying to return exists. It is found by the "String first = ...." line but when getproperty is called from the Compare method then it returns null.
You are passing "first", "second" to Compare. In your case both of them are strings and not objects, you need to pass "lsstt[j]" and "lsstt[iIndex]" to it.
if (Compare(lsstt[j], lsstt[iIndex]) < 0)
iIndex = j;

Updation of Dictionary Key Values which are in JSON array / ArrayLIst C#

Need to update ArrayList arlData with same data shown below but need to remove albumName values except top 1 i.e. albumName[0]´s value, Json data should update as shown in output below.
static void Main(string[] args)
{
/*Declaration */
ArrayList arlData = null;
arlData = new ArrayList();
Dictionary<string, object> data = null;
//Json data format
string json = #"{""Id"":""1"",""Count"":""2"",""musicName"":""test1"",""albumName"":[""1"", ""2"",""3""]}"
,json2 = #"{""Id"":""2"",""Count"":""1"",""musicName"":""test2"",""albumName"":[""4"", ""5""]}"
,json3 = #"{""Id"":""3"",""Count"":""1"",""musicName"":""test3"",""albumName"":[""6"", ""7""]}";
/*Adding data to array list */
arlData.Add(JsonConvert.DeserializeObject<Dictionary<string, object>>(json));
arlData.Add(JsonConvert.DeserializeObject<Dictionary<string, object>>(json2));
arlData.Add(JsonConvert.DeserializeObject<Dictionary<string, object>>(json3));
int intbytlen = 0;
if (arlData.Count > 0)
{
intbytlen = arlData.Count;
for (int iterator = 0; iterator < intbytlen; iterator++)
{
//Data fetch
data = (Dictionary<string, object>)arlData[iterator];
//Data serialization
Console.WriteLine(JsonConvert.SerializeObject(data, Formatting.Indented));
}
}
}
The output should be:
{"Id":"1","Count":"2","musicName":"test1","albumName":["1"]}
{"Id":"2","Count":"1","musicName":"test2","albumName":["4"]}
{"Id":"3","Count":"1","musicName":"test3","albumName":["6"]}
Consider using a model similar to this.
public class AlbumList
{
public int ID { get; set; }
public int Count { get; set; }
public string MusicName { get; set; }
public List<Album> AlbumName { get; set; }
}
public class Album
{
public int AlbumName { get; set; }
}
Then instantiating and fill objects with data, and add to a List<AlbumList>. You can then use Newtonsoft to serialise and deserialise when needed.
var albums = JsonConvert.DeserializeObject<List<AlbumList>>(json);
var json = JsonConvert.SerializeObject(albums, Formatting.Indented);
Once deserialised, access the List<AlbumList> and remove all items that aren't index 0.
for (int i = 1; i < AlbumList.Count; i++)
{
AlbumList.RemoveAt(i);
}
I found the simplest way, without creating class & properties to update dictionary key values and JSON data, just used type dynamic to fetch data from array list!
if (data.ContainsKey("albumName") && data["albumName"] != null)
{
//Assign specific data to type dynamic by deserialising the data
dynamic arryAlbumName = JsonConvert.DeserializeObject(data["albumName"].ToString());
if (arryAlbumName != null && arryAlbumName.Count > 0)
{
for (int count = 0; count < arryAlbumName.Count; count++)
{
if (count == 0)
{
ArrayList albumName = new ArrayList();
//Check for data exists and update the array value to arlData[]
if (!string.IsNullOrEmpty(arryAlbumName[count].ToString()))
{
albumName.Add(arryAlbumName[count]);
data.Remove("albumName");
data.Add("albumName", albumName);
arlData[iterator] = data;
}
}
}
}
}
The output is
{"Id":"1","Count":"2","musicName":"test1","albumName":["1"]}
{"Id":"2","Count":"1","musicName":"test2","albumName":["4"]}
{"Id":"3","Count":"1","musicName":"test3","albumName":["6"]}

Can't add Lazy initialized object to Generic List

I have generic list:
class BooksRegister <T>
{
private T[] Register;
public int Count { get; set; }
public BooksRegister()
{
Register = new T[100];
Count = 0;
}
public void Add(T value)
{
if (Count >= 100)
{
return;
}
Register[Count] = value;
Count ++;
}
}
then object class:
class Book
{
public String Author { get; set; }
public String Title { get; set; }
public int Quantity { get; set; }
public Book(String aut, String pav, int kiek)
{
this.Author = aut;
this.Title = pav;
this.Quantity = kiek;
}
public override string ToString()
{
return Author + " \"" + Title + "\" " + Quantity;
}
}
Then goes my Data class where I am reading information from file. I need to implement lazy initialization of object but when I do so I can't store my object in List.
public static void ReadBooks(BooksRegister<Book> allBooks)
{
StreamReader sr = new StreamReader("ListOfBooks.txt");
string line = "";
while ((line = sr.ReadLine()) != null)
{
string[] words = line.Split('|');
String tempAuthor = words[0];
String tempTitle = words[1];
int quant = Convert.ToInt32(words[2]);
Lazy<Book> tempas = new Lazy<Book>();
tempas.Value.Author = tempAuthor;
tempas.Value.Title = tempTitle;
tempas.Value.Quantity = quant;
allBooks.Add(tempas); // error here
}
How can I solve this problem? I have to use lazy initialization necessarily
If you must use lazy there are 2 ways:
You change you lazy initialization code with:
Lazy<Book> tempas = new Lazy<Book>(() => new Book(tempAuthor, tempTitle, quant));
allBooks.Add(tempas.Value);
What it does is defines an expression on how to initialize the book. This is a bad approach because you initialize lazy object on line one, and you initialize it on the second line, which basically makes using Lazy<Book> useless.
Another approach would be to change the method signature to
public static void ReadBooks(BooksRegister<Lazy<Book>> allBooks)
In this case your lazy initializing code would look like this:
Lazy<Book> tempas = new Lazy<Book>(() => new Book(tempAuthor, tempTitle, quant));
allBooks.Add(tempas);
One thing that is missing in this case is how to access Book in BooksRegister, as now it is write only object - you can add value, but there is no way to read it from outside the class.

C# Developing .Net3.5 using reflection to get/set values to nested properties and/or nested fields

I'm developing an app that works with data block classes inheritied from a base class and I am trying to use Reflection to drill down to properties/fields in my data block class. Since all the data block classes are derived/inherited from the base class (which contains a Size property) I can use a general variable of type base class to create an object in my app easily enough; I can also get/set properties at a top level. My problem occurs when the property is a field - I do not know how to get to the next level in the field to get to the base properties and/or fields, if applicable.
My BaseClass:
namespace MyBase {
public class BaseClass {
private int _size;
public BaseClass() { }
public BaseClass(int size) {
_size = size;
}
public int Size() {
return _size;
}
}
}
Data block class #1:
namespace DataBlock_class {
//Data block class #1: (contains simple properties - will be used later)
public class RecordBlock1_class : MyBase.BaseClass {
public byte Char { get; set; }
public byte Color { get; set; }
public RecordBlock1_class() : base(2) {
Char = 0;
Color = 0;
}
}
//Data block class #2: (contains simple properties)
public RecordBlock2_class : MyBase.BaseClass {
public bool Boolean1 { get; set; }
public byte Byte1 { get; set; }
public short Short1 { get; set; }
public ushort UShort1 { get; set; }
public RecordBlock2_class() : base(11) {
Boolean1 = false;
Byte1 = 0;
Short1 = 0;
UShort1 = 0;
}
}
//Data block class #3: (contains simple properties & fields)
public RecordBlock3_class : MyBase.BaseClass {
public int Int1 { get; set; }
public uint UInt1 { get; set; }
public RecordBlock1_class[] ArrayField1 { get; set; } // array of 12
public RecordBlock1_class[] ArrayField2 { get; set; } // array of 12
public RecordBlock1_class[] ArrayField3 { get; set; } // array of 12
public RecordBlock2_class() : base(34) {
Int1 = 0;
UInt1 = 0;
ArrayField1 = new RecordBlock1_class[12];
for(int x = 0; x < 12; x++) {
ArrayField1[x] = new RecordBlock1_class();
}
ArrayField2 = new RecordBlock1_class[12];
for(int x = 0; x < 12; x++) {
ArrayField2[x] = new RecordBlock1_class();
}
ArrayField3 = new RecordBlock1_class[12];
for(int x = 0; x < 12; x++) {
ArrayField3[x] = new RecordBlock1_class();
}
}
}
}
Since all my data block classes derive/inherit from MyBase.BaseClass, I can use this for my variable - I do not what type of data block class I will be processing at run time.
in my C# app, I have the following block of code:
string CSharpQualifiedName = "<this could be any of the data block classes above>";
// DataBlock_class.RecordBlock1_class
// DataBlock_class.RecordBlock2_class
// DataBlock_class.RecordBlock3_class
Using my MyBase.BaseClass variable, I can then instantiate a MyBase.BaseClass object:
MyBase.BaseClass baseClass = null;
Type baseClassType = Type.GetType(CSharpQualifiedName);
if(baseClassType == null) {
foreach(Assembly asm in AppDomain.CurrentDomain.GetAsseblies()) {
baseClassType= asm.GetType(CSharpQualifiedName);
if(baseClassType != null) {
baseClass = Activator.CreateInstance(baseClassType) as MyBase.BaseClass;
break;
}
}
}
Dealing with the first two data block classes are easy enough - I can using PropertyInfo to get/set values.
string fieldProperty = "<any property in the class>";
PropertyInfo pi = baseClass.GetType().GetProperty(fieldProperty);
Now, my proplem/issue is RecordBlock3_class - How do I get to one of the items in any of array fields/properties AND then to the Char/Color property in RecordBlock1_class???
I can use FieldInto to get to the ArrayFieldX fields, but I'm lost after that?
FieldInfo fi = baseClass.GetType().GetField(fieldProperty);
Any assistance/advice is greatly appreicated!! I will say one more thing, the data block classes can get a bit more complex as users create more nested class structures.
You can get element type of the array property by Reflection also, and then get its properties normally:
string fieldProperty = "ArrayField1";
System.Reflection.PropertyInfo pi = baseClass.GetType().GetProperty(fieldProperty);
if (pi.PropertyType.IsArray)
{
Type elementType = pi.PropertyType.GetElementType();
System.Reflection.PropertyInfo pi2 = elementType.GetProperty("Color");
}
Based on that, you can write simple yet more generic function that is traversing nested properties (to use also fields, simply modify below code):
static System.Reflection.PropertyInfo GetProperty(Type type, string propertyPath)
{
System.Reflection.PropertyInfo result = null;
string[] pathSteps = propertyPath.Split('/');
Type currentType = type;
for (int i = 0; i < pathSteps.Length; ++i)
{
string currentPathStep = pathSteps[i];
result = currentType.GetProperty(currentPathStep);
if (result.PropertyType.IsArray)
{
currentType = result.PropertyType.GetElementType();
}
else
{
currentType = result.PropertyType;
}
}
return result;
}
and then you can 'query' objects with 'paths':
PropertyInfo pi = GetProperty(c1.GetType(), "ArrayField1/Char");
PropertyInfo pi2 = GetProperty(c2.GetType(), "Color");
If you want to get values of object in this way, a method will be similar:
static object GetPropertyValue(object obj, string propertyPath)
{
System.Reflection.PropertyInfo result = null;
string[] pathSteps = propertyPath.Split('/');
object currentObj = obj;
for (int i = 0; i < pathSteps.Length; ++i)
{
Type currentType = currentObj.GetType();
string currentPathStep = pathSteps[i];
var currentPathStepMatches = Regex.Match(currentPathStep, #"(\w+)(?:\[(\d+)\])?");
result = currentType.GetProperty(currentPathStepMatches.Groups[1].Value);
if (result.PropertyType.IsArray)
{
int index = int.Parse(currentPathStepMatches.Groups[2].Value);
currentObj = (result.GetValue(currentObj) as Array).GetValue(index);
}
else
{
currentObj = result.GetValue(currentObj);
}
}
return currentObj;
}
And then you can get values queries, including arrays, for example:
var v = GetPropertyValue(baseClass, "ArrayField1[5]/Char");
Of course both methods requires some polishing of error handling etc.

Combining numbers and names collections

I have 2 List collections. One contains numbers, the other names. There are twice as many numbers as names(always). I want to take the first name from the collection and the first two numbers from the other collection then put them together in a 3rd user collection of (VentriloUser). Then the second name needs to be matched with the 3rd and 4th numbers and so on.
I was thinking something with a for or foreach loop, but I can't wrap my head around it right now.
public class VentriloUser
{
public VentriloUser(string name, int seconds, int ping)
{
Name = name; Seconds = seconds; Ping = ping;
}
public string Name { get; set; }
public int Ping { get; set; }
public int Seconds { get; set; }
}
public class Ventrilo
{
public Ventrilo(string statusurl)
{
StatusURL = statusurl;
}
public string StatusURL { get; set; }
public string HTML { get; set; }
public List<VentriloUser> Users { get; set; }
private Regex findNumbers = new Regex("\\<td width=\"10%\" bgcolor=\"#\\w{6}\"\\>\\<font color=\"#000000\">\\<div style=\"overflow:hidden;text-overflow:ellipsis\"\\>-?\\d+\\<");
private Regex findNames = new Regex("\\<td width=\"20%\" bgcolor=\"#\\w{6}\"\\>\\<font color=\"#000000\">\\<div style=\"overflow:hidden;text-overflow:ellipsis\"\\>\\b\\w+\\<");
private WebClient wClient = new WebClient();
public void DownloadHTML()
{
HTML = wClient.DownloadString(StatusURL);
}
public List<int> GetNumbers()
{
var rawnumbers = findNumbers.Matches(HTML);
var numbers = new List<int>();
foreach (var rawnumber in rawnumbers)
{
var match = Regex.Match(rawnumber.ToString(), "\\>\\-?\\d+\\<");
string number = Regex.Replace(match.ToString(), "\\<|\\>", "");
numbers.Add(Convert.ToInt32(number));
}
return numbers;
}
public List<string> GetNames()
{
var rawnames = findNames.Matches(HTML);
var names = new List<string>();
foreach (var rawname in rawnames)
{
var match = Regex.Match(rawname.ToString(), "\\>\\w+<");
string name = Regex.Replace(match.ToString(), "\\<|\\>", "");
names.Add(name);
}
return names;
}
public List<VentriloUser> GenerateUsers()
{
var numbers = GetNumbers();
var names = GetNames();
var users = new List<VentriloUser>();
}
}
I am a hobbyist, but hope to pursue a career one day. Any help is much appreciated. Thank you for your time.
Using LINQ:
var users = names.Select((name,idx) => new VentriloUser(name, numbers[idx*2], numbers[idx*2+1]))
.ToList();
Using loops:
var users = new List<VentriloUser>();
for (int i = 0; i < names.Count; i++)
{
var name = names[i];
int j = i * 2;
if (j >= numbers.Count - 1)
break; // to be safe...
users.Add(new VentriloUser(name, numbers[j], numbers[j + 1]));
}

Categories