Converting flat data structure into hierarchy Object using c# - c#-4.0

I have the following Flat Data Structure.
ParentAttributeId AttributeId List
----------------- ----------- ------
NULL 29 TestcaseCollection
29 30 EnclosureLeakageDielectricStrengthTest
30 31 DeviceID
30 32 ScannerOneLowChannel
30 33 ScannerTwoLowChannel
29 34 EnclosureLeakageLeakageCurrentTest
34 35 DeviceID
34 36 ScannerOneLowChannel
34 37 ScannerTwoLowChannel
29 38 PatientCircuitLeakageTest
38 39 DeviceID
38 40 ScannerOneLowChannel
38 41 ScannerTwoLowChannel
29 42 SIPSOPDielectricStrengthTest
42 44 ScannerOneHighChannel
42 45 ScannerOneLowChannel
42 46 ScannerTwoHighChannel
42 47 ScannerTwoLowChannel
29 48 SIPSOPLeakageCurrentTest
48 49 ScannerOneHighChannel
48 50 ScannerOneLowChannel
48 51 ScannerTwoHighChannel
48 52 ScannerTwoLowChannel
I need to convert above flat data structure into a hierarchy Object structure like below. So my Object looks like the "List" Column above. I am using SQL Stored Proc to get the above data. I am using C#.
Object hierarchy
29
|
30
| 31
| 32
| 33
|
34
| 35
| 36
|37
38
Any help would be greatly appreciated.
Regards
Niju

You could try something like this:
1) Create a node class
class Node
{
public int ParentId { get; private set; }
public int Id { get; private set; }
public string Label { get; private set; }
public Node Parent { get; set; }
public List<Node> Children { get; } = new List<Node>();
public Node(int parentId, int id, string lable)
{
ParentId = parentId;
Id = id;
Label = lable;
}
public void AddChild(Node child)
{
child.Parent = this;
Children.Add(child);
}
public void Trace(int indent = 1)
{
Enumerable.Range(0, indent).ToList().ForEach(i => Console.Write(" - "));
Console.WriteLine(Label);
Children.ForEach(c => c.Trace(indent + 1));
}
}
2) Create node objects from you flat data and add them to a dictionary
var data = new List<DataRow>() {
new DataRow { ParentId = 0, Id = 1, Label = "parent" },
new DataRow { ParentId = 1, Id = 2, Label = "child 1" },
new DataRow { ParentId = 1, Id = 3, Label = "child 2" },
new DataRow { ParentId = 2, Id = 4, Label = "grand child 1" },
new DataRow { ParentId = 2, Id = 5, Label = "grand child 2" }
};
Dictionary<int, Node> nodes = data.ToDictionary(d => d.Id, d => new Node(d.ParentId, d.Id, d.Label));
3) Build the hierarchy by looping through all nodes calling AddChild on the parent
foreach (var node in nodes.Skip(1))
nodes[node.Value.ParentId].AddChild(node.Value);
If you call Trace() on the top node, the output will look like this:
- parent
- - child 1
- - - grand child 1
- - - grand child 2
- - child 2

Have you looked at AutoMapper?
Not sure this is what you need but it's what I use to often convert from one format to an object model.
Another alternative might be to use LINQ to query the data you have and to create the model for you.
I think you can say something like, and this is untested;
select from dataList select new {....
where new would be the new object you are creating.
However, i think maybe the brute force approach of iterating through your list might still be the way.
edit
this might help.

Related

Properly parse MAC Address

When I use tools such as snmp-walk or snmp-get to query an OID with a return type of MacAddress, It'll always parse the data as a HexString and display it properly. Even when they don't have the MIBs loaded it'll still works.
bash#snmpwalk -v 2c -c public 10.1.2.3 1.3.6.1.4.1.14179.2.2.1.1
SNMPv2-SMI::enterprises.14179.2.2.1.1.1.16.189.24.206.212.64 = Hex-STRING: 10 BD 18 CE D4 40
SNMPv2-SMI::enterprises.14179.2.2.1.1.1.100.233.80.151.114.192 = Hex-STRING: 64 E9 50 97 72 C0
However, I can't seem to get the same result from Lextm.SharpSnmpLib (11.2.0). Data types of MacAddress don't get decoded correctly and it's a manual process to convert it to a proper MAC.
public void WalkTable()
{
const string baseOid = "1.3.6.1.4.1.14179.2.2.1.1"; //The entire table
const string community = "public";
var ep = new IPEndPoint(IPAddress.Parse("10.1.2.3"), 161);
var results = new List<Variable>();
Messenger.Walk(VersionCode.V2, ep, new OctetString(community), new ObjectIdentifier(baseOid), results, 60000, WalkMode.WithinSubtree);
foreach(var v in results)
Console.WriteLine(v.Data.ToString());
}
Am I doing something wrong or is this just how the library works?
You are outputting the MAC Address as ASCII instead of Hex. Here's a quick method I put together that will detect non-ascii characters and output as hex if any are found.
public void WalkTable()
{
const string baseOid = "1.3.6.1.4.1.14179.2.2.1.1"; //The entire table
const string community = "public";
var ep = new IPEndPoint(IPAddress.Parse("10.1.2.3"), 161);
var results = new List<Variable>();
Messenger.Walk(VersionCode.V2, ep, new OctetString(community), new ObjectIdentifier(baseOid), results, 60000, WalkMode.WithinSubtree);
foreach(var v in results)
//If the result is an OctetString, check for ascii, otherwise use ToString()
Console.WriteLine(v.Data.TypeCode.ToString()=="OctetString" ? DecodeOctetString(v.Data.ToBytes()) : v.Data.ToString())
}
}
public string DecodeOctetString(byte[] raw)
{
//First 2 bytes are the Type, so remove them
byte[] bytes = new byte[raw.Length - 2];
Array.Copy(raw, 2, bytes, 0, bytes.Length);
//Check if there are any non-ascii characters
bool ascii = true;
foreach (char c in Encoding.UTF8.GetString(bytes))
{
if (c >= 128)
{
ascii = false;
}
}
//If it's all ascii, return as ascii, else convert to hex
return ascii ? Encoding.ASCII.GetString(bytes) : BitConverter.ToString(bytes);
}

How to manage several Serial messages in processing

I am reading the UID of my RFID card and storing it in a variable called myUID.
After that I am authorizing to the card with the factory key and read block number 4 (which has been written to earlier) and store it in a string readBlock.
On the Arduino, I print out the variables onto the serial interface like so.
Serial.println(myUID);
Serial.println(readBlock);
On the client side, I use a Java program that reads in serial data. My program uses the Processing Library.
Serial mySerial;
PrintWriter output;
void setup() {
output = createWriter( "data.txt" );
mySerial = new Serial( this, Serial.list()[0], 9600 );
mySerial.bufferUntil('\n');
}
void draw(){
while (mySerial.available() > 0) {
String inBuffer = mySerial.readString();
if (inBuffer != null)
output.println(inBuffer);
}
}
void keyPressed() { // Press a key to save the data
output.flush(); // Write the remaining data
output.close(); // Finish the file
exit(); // Stop the program
}
Now my data.txt is expected to look like
xxx xxx xxx xxx (uid of card)
00 00 00 00 00 00 00 00 ... (read block from card)
but looks like
237 63 58 1
07
37 37 95
37
97 98 50 54 37 5
4 55 102 55 52
45 98
I have tried several things like readStringUntil('\n'); in the Processing Library but without success.
For everyone interested, I have fixed the problem myself with many hours of searching Google, so maybe this will help someone in the future:
I could fix it with this code:
import processing.serial.*;
int count = 0;
String input = "";
String fileName = dataPath("SET FILEPATH HERE");
Serial mySerial;
import java.io.*;
void setup() {
mySerial = new Serial(this, Serial.list()[0], 9600);
mySerial.bufferUntil('\n');
File f = new File(fileName);
if (f.exists()) {
f.delete();
}
}
void draw(){}
// listen to serial events happening
void serialEvent(Serial mySerial){
input = mySerial.readStringUntil('\n');
write(input, count);
count++;
}
// function for writing the data to the file
void write(String inputString, int counter) {
// should new data be appended or replace any old text in the file?
boolean append = false;
// just for my purpose, because I have got two lines of serial which need to get written to the file
//(Line 1: UID of card, Line 2: Read block of card)
if(counter < 2){
append = true;
}
else{
count = 0;
}
try {
File file = new File("D:/xampp/htdocs/pizza/src/rfid/data.txt");
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file, append);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bw);
pw.write(inputString + '\n');
pw.close();
}
catch(IOException ioe) {
System.out.println("Exception ");
ioe.printStackTrace();
}
}

converting strings within Entity Framework query

The following query works perfectly fine and populates its dropdown list. The data in the data base is stored in all uppercase, ie PALM BEACH. I want to convert it to Proper case, which obviously i can do after the fact by iterating through the returned list and reformatting BUT I should be able to do it with in the query itself. The following query works fine.
Dim citylist As List(Of String) = (From c In ctx.ziptaxes
Where c.StateID = ddlStates.SelectedIndex
Order By c.City Ascending
Select c.City).ToList()
But if i try to convert it to some thing like this, it fails
Dim citylist As List(Of String) = (From c In ctx.ziptaxes
Where c.StateID = ddlStates.SelectedIndex
Let cityname = StrConv(c.City, VbStrConv.ProperCase)
Order By cityname Ascending
Select cityname).ToList()
I've tried using culture info and String.Format(c.City, vbProperCase) too and nothing other than the original query works. Any help appreciated.
ADDENDUM:
Well some further research is telling me that .Net objects like string conversion and cultureinfo cannot be used prior to the query being run. If that's the case it explains why it isn't working. The following solves my problem BUT I would still like to know if there is way to do it within the LINQ to EF.
Dim citylist As List(Of String) = (From c In ctx.ziptaxes
Where c.StateID = ddlStates.SelectedIndex
Order By c.City Ascending
Select c.City).ToList()
If citylist.Count > 0 Then
For i As Integer = 0 To citylist.Count - 1
citylist(i) = StrConv(citylist(i).ToLower(), vbProperCase)
Next
With ddlCity
.Items.Clear()
.DataSource = citylist.Distinct()
.DataBind()
.Items.Insert(0, "Select a city")
.SelectedIndex = 0
End With
End If
You can do the conversion in your SELECT. Here's an example (with an over-simplified City name converter):
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace LinqQuestion
{
[TestFixture]
public class StackOverflowTests
{
private IEnumerable<City> _cities;
[TestFixtureSetUp]
public void Arrange()
{
_cities = new List<City>
{
new City { Id = 1, Name = "FLINT", StateId = 1 },
new City { Id = 2, Name = "SAGINAW", StateId = 1 },
new City { Id = 3, Name = "DETROIT", StateId = 1 },
new City { Id = 4, Name = "FLint", StateId = 1 }
};
}
[Test]
public void TestCountryQuery()
{
var data = _cities
.Where(c => c.StateId == 1)
.OrderBy(c => c.Name)
.Select(c => StrConv(c.Name))
.Distinct().ToList();
Assert.That(data.Count == 3);
}
private static string StrConv(string original)
{
var firstLetter = original.Substring(0, 1).ToUpper();
var theRest = original.Substring(1, original.Length - 1).ToLower();
return firstLetter + theRest;
}
}
public class City
{
public int Id { get; set; }
public int StateId { get; set; }
public string Name { get; set; }
}
}

Monotouch mapkit mkannotation collection gives errors

New to monotouch aka xamarin ios. Trying to get a robust mapkit working that can take a number of pins. Experimenting with a basic example that I've cobbled together from a variety of sources that I could find.
Getting a sporadic SIGSEGV error. Seems like some sort of memory error when the pins are clicked to show an alert box which sometimes works and sometimes doesnt.
I'm not sure where I'm going wrong. Is this along the right lines? Here's the code
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.MapKit;
using MonoTouch.CoreLocation;
using System.Collections.Generic;
namespace singleview
{
public partial class singleviewViewController : UIViewController
{
public singleviewViewController () : base ("singleviewViewController", null)
{
}
private LocationService locationService;
private MKMapView mapView;
List<BasicMapAnnotation> pins = new List<BasicMapAnnotation>();
public override void ViewDidLoad()
{
base.ViewDidLoad();
// example of a series of map points
pins.Add(new BasicMapAnnotation(new CLLocationCoordinate2D(37.766995, -122.419580), "h", "sub1", "id1"));
pins.Add(new BasicMapAnnotation(new CLLocationCoordinate2D(37.776880, -122.418485), "i", "sub2", "id2"));
pins.Add(new BasicMapAnnotation(new CLLocationCoordinate2D(37.786775, -122.417390), "j", "sub3", "id3"));
pins.Add(new BasicMapAnnotation(new CLLocationCoordinate2D(37.796685, -122.416283), "k", "sub4", "id4"));
var currentLocation = new LocationService().GetCurrentLocation();
var visibleRegion = BuildVisibleRegion(currentLocation);
mapView = BuildMapView(true);
mapView.SetRegion(visibleRegion, true);
this.View.AddSubview(mapView);
// i have a vague idea that this delegate helps to redraw pins as user moves around screen
mapView.Delegate = new MapViewDelegate();
// this pin sometimes has a working callout that activates an alert and sometimes doesnt
var testAnnotationX = new BasicMapAnnotation (new CLLocationCoordinate2D(37.786999,-122.500222),
"made in viewdidload", "outside", "id5");
mapView.AddAnnotation(testAnnotationX);
// this pin collection also sometimes works but most often not
mapView.AddAnnotations(pins.ToArray());
}
private MKMapView BuildMapView(bool showUserLocation)
{
var view = new MKMapView()
{
ShowsUserLocation = showUserLocation,
};
view.Delegate = new MapViewDelegate();
var testAnnotationY = new BasicMapAnnotation (new CLLocationCoordinate2D(37.800000, -122.450777),
"made in buildmapview", "inside", "id6");
view.AddAnnotation(testAnnotationY);
view.SizeToFit();
view.Frame = new RectangleF(0, 0, this.View.Frame.Width, this.View.Frame.Height);
return view;
}
protected class MapViewDelegate : MKMapViewDelegate {
protected string annotationIdentifier = "BasicAnnotation";
UIButton detailButton; // avoid GC
public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation)
{
if (annotation is MKUserLocation) return null; //ignore user marker
annotationIdentifier = (annotation as BasicMapAnnotation).Id;
// try and dequeue the annotation view
MKAnnotationView annotationView = mapView.DequeueReusableAnnotation(annotationIdentifier);
// if we couldn't dequeue one, create a new one
if (annotationView == null)
{
annotationView = new MKPinAnnotationView(annotation, annotationIdentifier);
//annotationView.RightCalloutAccessoryView = new UIButton(UIButtonType.DetailDisclosure); //- not required as its at bottom??
// configure our annotation view properties
annotationView.CanShowCallout = true;
(annotationView as MKPinAnnotationView).AnimatesDrop = true;
(annotationView as MKPinAnnotationView).PinColor = MKPinAnnotationColor.Green;
annotationView.Selected = true;
// you can add an accessory view; in this case, a button on the right and an image on the left
detailButton = UIButton.FromType(UIButtonType.DetailDisclosure);
detailButton.TouchUpInside += (s, e) => {
Console.WriteLine ("Clicked");
new UIAlertView("Annotation Clicked", "You clicked on " +
(annotation as MKAnnotation).Coordinate.Latitude.ToString() + ", " +
(annotation as MKAnnotation).Coordinate.Longitude.ToString() , null, "OK", null).Show();
};
annotationView.RightCalloutAccessoryView = detailButton;
}
else // if we did dequeue one for reuse, assign the annotation to it
annotationView.Annotation = annotation;
/*
// configure our annotation view properties
annotationView.CanShowCallout = true;
(annotationView as MKPinAnnotationView).AnimatesDrop = true;
(annotationView as MKPinAnnotationView).PinColor = MKPinAnnotationColor.Green;
annotationView.Selected = true;
*/
// fix and uncomment
//annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromBundle("29_icon.png"));
return annotationView;
}
// as an optimization, you should override this method to add or remove annotations as the
// map zooms in or out.
public override void RegionChanged (MKMapView mapView, bool animated) {}
}
private MKCoordinateRegion BuildVisibleRegion(CLLocationCoordinate2D currentLocation)
{
var span = new MKCoordinateSpan(0.2,0.2);
var region = new MKCoordinateRegion(currentLocation,span);
return region;
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
}
public class BasicMapAnnotation : MKAnnotation{
public override CLLocationCoordinate2D Coordinate {get;set;}
string title, subtitle;
public override string Title { get{ return title; }}
public override string Subtitle { get{ return subtitle; }}
public string Id {get ;set;}
public BasicMapAnnotation (CLLocationCoordinate2D coordinate, string title, string subtitle, string id) {
this.Coordinate = coordinate;
this.title = title;
this.subtitle = subtitle;
this.Id = id;
}
}
public class LocationService
{
private CLLocationManager locationManager;
public LocationService()
{
locationManager = new CLLocationManager();
}
public CLLocationCoordinate2D GetCurrentLocation()
{
//dirty for now just to get some info.
locationManager.StartUpdatingLocation();
while(locationManager.Location == null);
locationManager.StopUpdatingLocation();
//return new CLLocationCoordinate2D ( 37.786995, -122.419280);
return locationManager.Location.Coordinate;
}
}
}
Error:
Stacktrace:
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at singleview.Application.Main (string[]) [0x00000] in .../singleview/Main.cs:17
at (wrapper runtime-invoke) .runtime_invoke_void_object (object,intptr,intptr,intptr)
Native stacktrace:
0 singleview 0x00091eac mono_handle_native_sigsegv + 284
1 singleview 0x00005788 mono_sigsegv_signal_handler + 248
2 libsystem_c.dylib 0x938658cb _sigtramp + 43
3 ??? 0xffffffff 0x0 + 4294967295
4 UIKit 0x0274f258 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
5 UIKit 0x02810021 -[UIControl sendAction:to:forEvent:] + 66
6 UIKit 0x0281057f -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 578
7 UIKit 0x0280f6e8 -[UIControl touchesEnded:withEvent:] + 546
8 UIKit 0x0277ecef -[UIWindow _sendTouchesForEvent:] + 846
9 UIKit 0x0277ef02 -[UIWindow sendEvent:] + 273
10 UIKit 0x0275cd4a -[UIApplication sendEvent:] + 436
11 UIKit 0x0274e698 _UIApplicationHandleEvent + 9874
12 GraphicsServices 0x04d40df9 _PurpleEventCallback + 339
13 GraphicsServices 0x04d40ad0 PurpleEventCallback + 46
14 CoreFoundation 0x012bfbf5 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
15 CoreFoundation 0x012bf962 __CFRunLoopDoSource1 + 146
16 CoreFoundation 0x012f0bb6 __CFRunLoopRun + 2118
17 CoreFoundation 0x012eff44 CFRunLoopRunSpecific + 276
18 CoreFoundation 0x012efe1b CFRunLoopRunInMode + 123
19 GraphicsServices 0x04d3f7e3 GSEventRunModal + 88
20 GraphicsServices 0x04d3f668 GSEventRun + 104
21 UIKit 0x0274bffc UIApplicationMain + 1211
22 ??? 0x0f4d71ad 0x0 + 256733613
23 ??? 0x0f4d4e40 0x0 + 256724544
24 ??? 0x0f4d4a48 0x0 + 256723528
25 ??? 0x0f4d4b9e 0x0 + 256723870
26 singleview 0x00009b52 mono_jit_runtime_invoke + 722
27 singleview 0x0016d02e mono_runtime_invoke + 126
28 singleview 0x00171224 mono_runtime_exec_main + 420
29 singleview 0x00176615 mono_runtime_run_main + 725
30 singleview 0x000671e5 mono_jit_exec + 149
31 singleview 0x00204fd4 main + 1988
32 singleview 0x00002b75 start + 53
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
=================================================================
Looks like the good old GC Error.
Take a look at the Monotouch-Samples App exactly this Class and Line:
https://github.com/xamarin/monotouch-samples/blob/master/MapCallouts/MainViewController.cs#L108
You need to store all the Pinviews within some Collection, so the Garbage Collection doesn't try to collect them.
What about the 'var testAnnotationX'? You might need to move that as well.

Find all objects in List<T> with same property value

I have a class Card, which has property Rank (1,2,3 etc) and I have a list of Cards and I wish to find all the Cards with the same Rank value in that list.
The list of Cards is sorted by Rank beforehand.
What would be the fasted way in .NET (using LINQ, if possible) to find all the objects with the same property value.
I don't know what the property value is beforehand, so I have to go through and compare. Until now I've been looping and keeping references to previous objects to compare, but I was wondering if there is not some easier way to do this?
Point is I need to be able to find N elements in a list with the same property value.
There might not be, but I thought I'd still ask.
You could group the cards by rank:
public class Card
{
public int Rank { get; set; }
}
class Program
{
static void Main()
{
var cards = new[]
{
new Card { Rank = 1 },
new Card { Rank = 2 },
new Card { Rank = 3 },
new Card { Rank = 2 },
new Card { Rank = 1 },
};
var groups = cards.GroupBy(x => x.Rank);
foreach (var group in groups)
{
Console.WriteLine("Cards with rank {0}", group.Key);
foreach (var card in group)
{
Console.WriteLine(card.Rank);
}
}
}
}
easiest would be to use linq
var results = myCardList.Select( c=>c.rank == myRank );
then you can iterate or convert to list.
Use Enumerable.ToLookup. The cards does not have to be sorted beforehand.
If you have a class
public class Card
{
public string Name { get; set; }
public int Rank { get; set; }
}
Then you can create a Lookup that groups per Rank like this
var cards = new Card[]{
new Card{Rank = 1, Name = "A"},
new Card{Rank = 1, Name = "B"},
new Card{Rank = 2, Name = "C"},
new Card{Rank = 3, Name = "D"},
};
var cardsByRank = cards.ToLookup(card => card.Rank);
foreach (var cardRankGroup in cardsByRank)
{
Console.WriteLine("KEY: " + cardRankGroup.Key);
foreach (var card in cardRankGroup)
{
Console.WriteLine(" Card: " + card.Name);
}
}
with the output
KEY: 1
Card: A
Card: B
KEY: 2
Card: C
KEY: 3
Card: D
Edit
if you want to extract all cards for a given Rank you can use rank as index to the lookup
foreach (var card in cardsByRank[2])
{
Console.WriteLine(" Card: " + card.Name);
}
Hey Tony, are you looking for something link this?
List<Card> rankedCards = cards.Where(o=> o.Rank == rank).ToList()
This should return a list of Cards that match the variable "rank" which I assume contains an int containing the value of Rank you want to match.

Resources