USBDeviceInfo/ManagementObjectSearcher gives Arguments that where´nt asked for - c#

I have some code i wrote for finding the COM-Port of a certain Motor-Controller, based off of this Article:
Getting Serial Port Information
Since this Code doesn´t explicitely look for ComPorts, but for Device Names and Infos, I played around a bit and found out that when you look for a certain device in the resulting list, referenced by name, and write that to a *.txt file, the COMPort shows up in (brackets) after the name, like so: Devicename (COM5).
This I used to write that information to a string using Array.Find, and from then on it´s just selecting the number to connect to.
My Problem is that i don´t want to loop through ALL devices, but just until the one I´m looking for is found, and then break the loop.
This, however, results in a string[1] Array without the COMPort attached to entries, opposed to a string[2] Array with ComPort attached if I don´t break the loop.
I want to know why the COMPort gets attached in the first place (my guess is collection.Dispose), and why breaking the loop kills that "function/bug/whatever".
{
public static void ComPortSelectionMain(/*string[] args*/)
{
string ComDummy; // ComPort, ComPortString;
int ComNumber = 0;
var usbDevices = GetUSBDevices();
var ComList = new List<string>();
foreach (var usbDevice in usbDevices)
{
if (usbDevice.Description == "PI C-863")
{
//Console.WriteLine("Device ID: {0}, PNP Device ID: {1}, Description: {2}", usbDevice.DeviceID, usbDevice.PnpDeviceID, usbDevice.Description);
ComList.Add(usbDevice.Name); //Add USB Device
}
}
var ComArray = ComList.ToArray();
var target = "PI C-863 (COM";
// var target2 = ")";
int arrayindex = 0;
int start = 0, stop = 0;
string targetname = "PI C-863";
string test = (Array.Find(ComArray, element => element.Contains(targetname)));
//Console.WriteLine("Test: " + test);
if (test == targetname) //look if comarray contains target
{
//int index = Array.FindIndex(ComArray, item => item == "("); // row.Contains(targetname));
int indexsigned = Array.IndexOf(ComArray, target);
int index = Math.Abs(indexsigned);
start = ComArray[index].IndexOf('(') + 1;
arrayindex = index;
stop = ComArray[index].IndexOf(')');
}
int COMlength = 0, portlength = 0, pos = 0;
COMlength = stop - start;
portlength = stop - start - 3;
pos = start + 3;
//Console.WriteLine("COM: {0}", ComArray[arrayindex]);
ComDummy = ComArray[arrayindex].Substring(start, COMlength);
//Console.WriteLine("ComDummy: {0}", ComDummy);
ComNumber = Convert.ToInt32(ComArray[arrayindex].Substring(pos, portlength));
Console.WriteLine("ComPort Number: {0}", ComNumber);
Console.Read();
}
static List<USBDeviceInfo> GetUSBDevices()
{
List<USBDeviceInfo> devices = new List<USBDeviceInfo>();
ManagementObjectCollection collection;
using (var searcher = new ManagementObjectSearcher(#"Select * From Win32_PnPEntity"))
collection = searcher.Get();
bool kappa = true;
foreach (var device in collection)
{
devices.Add(new USBDeviceInfo(
(string)device.GetPropertyValue("DeviceID"),
(string)device.GetPropertyValue("PNPDeviceID"),
(string)device.GetPropertyValue("Description"),
(string)device.GetPropertyValue("Name"),
(string)device.GetPropertyValue("Service")
));
***//if ((devices.Exists(element => element.Description == "PI C-863")) && kappa)
//{
// Console.WriteLine("Found PI C-863!");
// kappa = false;
// //break;
//}*** <<< THIS IF() BREAKS MY CODE
}
collection.Dispose();
return devices;
}
}
class USBDeviceInfo
{
public USBDeviceInfo(string deviceID, string pnpDeviceID, string description, string name, string var)
{
this.DeviceID = deviceID;
this.PnpDeviceID = pnpDeviceID;
this.Description = description;
this.Name = name;
this.Var = var;
}
public string DeviceID { get; private set; }
public string PnpDeviceID { get; private set; }
public string Description { get; private set; }
public string Name { get; private set; }
public string Var { get; private set; }
}
The if(devices.Exist) question breaks my code if I use it and let if break the loop, can somebody explain why, and what i could do?
(Code works fine so far, but not being able to break the loop slows it down quite a bit)
Thanks in advance :)
Regards, Cinnabar

You should try :
static List<USBDeviceInfo> GetUSBDevices()
{
ManagementObjectCollection collection;
using (var searcher = new ManagementObjectSearcher(#"Select * From Win32_PnPEntity"))
collection = searcher.Get();
foreach (var device in collection)
{
if(device.GetPropertyValue("Description").Equals("PI C-863"))
{
Console.WriteLine("Found PI C-863!");
break;
}
}
collection.Dispose();
return devices;
}
I did not test it, but i think iterating over a List while adding into it could be the issue.

SerialPort.GetPortNames() reads the comports on computer. Use following code to read the comports and fill combo box (dropdown).
private void refreshPortChoices()
{
int selectedPortIndex = this.cbbPortName.SelectedIndex;
this.cbbPortName.Items.Clear();
this.cbbPortName.Items.AddRange(SerialPort.GetPortNames());
if (selectedPortIndex < this.cbbPortName.Items.Count)
{
this.cbbPortName.SelectedIndex = selectedPortIndex;
}
if (this.cbbPortName.Items.Count == 0)
{
this.cbbPortName.Items.Add("none");
this.btnConnection.Enabled = false;
}
else
{
this.btnConnection.Enabled = true;
}
}

Related

Read lines of data from CSV then display data

I have to read info from a txt file, store it in a manner (array or list), then display the data. Program must include at least one additional class.
I've hit a wall and can't progress.
string, string, double, string
name,badge,salary,position
name,badge,salary,position
name,badge,salary,position
I'm sorry and I know the code below is disastrous but I'm at a loss and am running out of time.
namespace Employees
{
class Program
{
static void Main()
{
IndividualInfo collect = new IndividualInfo();
greeting();
collect.ReadInfo();
next();
for (int i = 0; i < 5; i++)
{
displayInfo(i);
}
exit();
void greeting()
{
Console.WriteLine("\nWelcome to the Software Development Company\n");
}
void next()
{
Console.WriteLine("\n*Press enter key to display information . . . *");
Console.Read();
}
void displayInfo(int i)
{
Console.WriteLine($"\nSoftware Developer {i + 1} Information:");
Console.WriteLine($"\nName:\t\t\t{collect.nameList[i]}");
}
void exit()
{
Console.WriteLine("\n\n*Press enter key to exit . . . *");
Console.Read();
Console.Read();
}
}
}
}
class IndividualInfo
{
public string Name { get; set; }
//public string Badge{ get; set; }
//public string Position{ get; set; }
//public string Salary{ get; set; }
public void ReadInfo()
{
int i = 0;
string inputLine;
string[] eachLine = new string[4];
string[,] info = new string[5, 4]; // 5 developers, 4x info each
StreamReader file = new StreamReader("data.txt");
while ((inputLine = file.ReadLine()) != null)
{
eachLine = inputLine.Split(',');
for (int x = 0; x < 5; x++)
{
eachLine[x] = info[i, x];
x++;
}
i++;
}
string name = info[i, 0];
string badge = info[i, 1];
string position = info[i, 2];
double salary = Double.Parse(info[i, 3]);
}
public List<string> nameList = new List<string>();
}
So far I think I can collect it with a two-dimensional array, but a List(s) would be better. Also, the code I've posted up there won't run because I can't yet figure out a way to get it to display. Which is why I'm here.
using System.IO;
static void Main(string[] args)
{
using(var reader = new StreamReader(#"C:\test.csv"))
{
List<string> listA = new List<string>();
List<string> listB = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(';');
listA.Add(values[0]);
listB.Add(values[1]);
}
}
}
https://www.rfc-editor.org/rfc/rfc4180
or
using Microsoft.VisualBasic.FileIO;
var path = #"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
// Skip the row with the column names
csvParser.ReadLine();
while (!csvParser.EndOfData)
{
// Read current line fields, pointer moves to the next line.
string[] fields = csvParser.ReadFields();
string Name = fields[0];
string Address = fields[1];
}
}
http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html
or
LINQ way:
var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
select (from piece in line
select piece);
^^Wrong - Edit by Nick
It appears the original answerer was attempting to populate csv with a 2 dimensional array - an array containing arrays. Each item in the first array contains an array representing that line number with each item in the nested array containing the data for that specific column.
var csv = from line in lines
select (line.Split(',')).ToArray();
This question was fully addressed here:
Reading CSV file and storing values into an array

fastest starts with search algorithm

I need to implement a search algorithm which only searches from the start of the string rather than anywhere within the string.
I am new to algorithms but from what I can see it seems as though they go through the string and find any occurrence.
I have a collection of strings (over 1 million) which need to be searched everytime the user types a keystroke.
EDIT:
This will be an incremental search. I currently have it implemented with the following code and my searches are coming back ranging between 300-700ms from over 1 million possible strings. The collection isnt ordered but there is no reason it couldnt be.
private ICollection<string> SearchCities(string searchString) {
return _cityDataSource.AsParallel().Where(x => x.ToLower().StartsWith(searchString)).ToArray();
}
I've adapted the code from this article from Visual Studio Magazine that implements a Trie.
The following program demonstrates how to use a Trie to do fast prefix searching.
In order to run this program, you will need a text file called "words.txt" with a large list of words. You can download one from Github here.
After you compile the program, copy the "words.txt" file into the same folder as the executable.
When you run the program, type a prefix (such as prefix ;)) and press return, and it will list all the words beginning with that prefix.
This should be a very fast lookup - see the Visual Studio Magazine article for more details!
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
var trie = new Trie();
trie.InsertRange(File.ReadLines("words.txt"));
Console.WriteLine("Type a prefix and press return.");
while (true)
{
string prefix = Console.ReadLine();
if (string.IsNullOrEmpty(prefix))
continue;
var node = trie.Prefix(prefix);
if (node.Depth == prefix.Length)
{
foreach (var suffix in suffixes(node))
Console.WriteLine(prefix + suffix);
}
else
{
Console.WriteLine("Prefix not found.");
}
Console.WriteLine();
}
}
static IEnumerable<string> suffixes(Node parent)
{
var sb = new StringBuilder();
return suffixes(parent, sb).Select(suffix => suffix.TrimEnd('$'));
}
static IEnumerable<string> suffixes(Node parent, StringBuilder current)
{
if (parent.IsLeaf())
{
yield return current.ToString();
}
else
{
foreach (var child in parent.Children)
{
current.Append(child.Value);
foreach (var value in suffixes(child, current))
yield return value;
--current.Length;
}
}
}
}
public class Node
{
public char Value { get; set; }
public List<Node> Children { get; set; }
public Node Parent { get; set; }
public int Depth { get; set; }
public Node(char value, int depth, Node parent)
{
Value = value;
Children = new List<Node>();
Depth = depth;
Parent = parent;
}
public bool IsLeaf()
{
return Children.Count == 0;
}
public Node FindChildNode(char c)
{
return Children.FirstOrDefault(child => child.Value == c);
}
public void DeleteChildNode(char c)
{
for (var i = 0; i < Children.Count; i++)
if (Children[i].Value == c)
Children.RemoveAt(i);
}
}
public class Trie
{
readonly Node _root;
public Trie()
{
_root = new Node('^', 0, null);
}
public Node Prefix(string s)
{
var currentNode = _root;
var result = currentNode;
foreach (var c in s)
{
currentNode = currentNode.FindChildNode(c);
if (currentNode == null)
break;
result = currentNode;
}
return result;
}
public bool Search(string s)
{
var prefix = Prefix(s);
return prefix.Depth == s.Length && prefix.FindChildNode('$') != null;
}
public void InsertRange(IEnumerable<string> items)
{
foreach (string item in items)
Insert(item);
}
public void Insert(string s)
{
var commonPrefix = Prefix(s);
var current = commonPrefix;
for (var i = current.Depth; i < s.Length; i++)
{
var newNode = new Node(s[i], current.Depth + 1, current);
current.Children.Add(newNode);
current = newNode;
}
current.Children.Add(new Node('$', current.Depth + 1, current));
}
public void Delete(string s)
{
if (!Search(s))
return;
var node = Prefix(s).FindChildNode('$');
while (node.IsLeaf())
{
var parent = node.Parent;
parent.DeleteChildNode(node.Value);
node = parent;
}
}
}
}
A couple of thoughts:
First, your million strings need to be ordered, so that you can "seek" to the first matching string and return strings until you no longer have a match...in order (seek via C# List<string>.BinarySearch, perhaps). That's how you touch the least number of strings possible.
Second, you should probably not try to hit the string list until there's a pause in input of at least 500 ms (give or take).
Third, your queries into the vastness should be async and cancelable, because it's certainly going to be the case that one effort will be superseded by the next keystroke.
Finally, any subsequent query should first check that the new search string is an append of the most recent search string...so that you can begin your subsequent seek from the last seek (saving lots of time).
I suggest using linq.
string x = "searchterm";
List<string> y = new List<string>();
List<string> Matches = y.Where(xo => xo.StartsWith(x)).ToList();
Where x is your keystroke search text term, y is your collection of strings to search, and Matches is the matches from your collection.
I tested this with the first 1 million prime numbers, here is the code adapted from above:
Stopwatch SW = new Stopwatch();
SW.Start();
string x = "2";
List<string> y = System.IO.File.ReadAllText("primes1.txt").Split(' ').ToList();
y.RemoveAll(xo => xo == " " || xo == "" || xo == "\r\r\n");
List <string> Matches = y.Where(xo => xo.StartsWith(x)).ToList();
SW.Stop();
Console.WriteLine("matches: " + Matches.Count);
Console.WriteLine("time taken: " + SW.Elapsed.TotalSeconds);
Console.Read();
Result is:
matches: 77025
time taken: 0.4240604
Of course this is testing against numbers and I don't know whether linq converts the values before, or if numbers make any difference.

Set a string on a string referenced by string array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
string db;
ComboBox fieldBox = new ComboBox()
TextBox ValueBox = new TextBox()
ListBox dbValues = new ListBox()
private void LoadDB()
{
//Structure
string myStruct = "NAME\nAGE\nSEX\nSKILL
db = "John\t20\tMale\tNoob\n
Joe\t20\tMale\tMedium\n
Jessica\t27\tFemale\tExpert\n
John\t21\tMale\tMedium
";
//Load struct to combobox
string[] mbstr = myStruct.Split('\n');
for (int i = 0; i < mbstr.Length; i++)
{
fieldBox.Items.Add(mbstr[i]);
}
string[] db2 = db.Split('\n');
for (int i = 1; i < db2.Length - 1; i++)
{
//Display name and age in combobox
dbValues.Items.Add(db2[i].Split('\t')[0] + " - " + db2[i].Split('\t')[1]);
}
}
void ValueBoxKeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode != Keys.Enter)
return;
db.Split('\n')[dbValues.SelectedIndex].Split('\t')[fieldBox.SelectedIndex] = valueBox.Text;
MessageBox.Show("Value set: " +
db.Split('\n')[dbValues.SelectedIndex + 1].Split('\t')[fieldBox.SelectedIndex]
+ " to " + valueBox.Text + ".");
}
This is where it fails:
db.Split('\n')[dbValues.SelectedIndex].Split('\t')[fieldBox.SelectedIndex] = valueBox.Text;
I tried this, and tried to assign to db, but not working though. My original string is unchanged.
I do not want to convert to list and string back, i want to change directly.
How can i do this?
Your first problem is your string: unless you use # escaping you can't have your string cross multiple lines, and if you use # escaping you can't do \t or \n and retain their escaped meaning of tab and newline.
The second problem is a fundamental misunderstanding of the .NET string, string's are immutable. Split will create an array, there is no reference back to the original string, or the second array your splitting. You would need to do something like:
[TestClass]
public class StringTest
{
public TestContext TestContext { get; set; }
[TestMethod]
public void RewriteString()
{
var str = "Garry\t19\tMale\tNoob\n" +
"Joe\t25\tMale\tMedium\n" +
"Gary\t33\tFemale\tExpert";
var rows = str.Split('\n');
var columns = rows[0].Split('\t');
columns[0] = "Jerry";
rows[0] = string.Join("\t", columns);
str = string.Join("\n", rows);
TestContext.WriteLine(str);
}
}
Test Name: RewriteString
Test Outcome: Passed
Result StandardOutput: TestContext Messages:
Jerry 19 Male Noob
Joe 25 Male Medium
Gary 33 Female Expert
Would really hope there would be an easier way to do this, possibly with a Regex?
Now to really look at your (new) question. I have refactored exactly what you have, as I do not know your data situation I'm not entirely sure using a string as a database is a good idea: (this will compile without any references because of the use of dynamic).
public class SomeView
{
string db;
dynamic fieldBox = null;
dynamic valueBox = null;
dynamic dbValues = null;
dynamic MessageBox = null;
private void LoadDB()
{
//Structure
string myStruct = "NAME\nAGE\nSEX\nSKILL";
db = "John\t20\tMale\tNoob\n" +
"Joe\t20\tMale\tMedium\n" +
"Jessica\t27\tFemale\tExpert\n" +
"John\t21\tMale\tMedium";
//Load struct to combobox
string[] mbstr = myStruct.Split('\n');
for (int i = 0; i < mbstr.Length; i++)
{
fieldBox.Items.Add(mbstr[i]);
}
string[] db2 = db .Split('\n');
for (int i = 1; i < db2.Length - 1; i++)
{
var data = db2[i].Split('\t'); //expensive only do once
//Display name and age in combobox
dbValues.Items.Add(data[0] + " - " + data[1]);
}
}
protected string Transform(string value, int row, int column, string replacement, out string old)
{
var rows = value.Split('\n');
var columns = rows[row].Split('\t');
old = columns[column];
columns[column] = replacement;
rows[row] = string.Join("\t", columns);
return string.Join("\n", rows);
}
void ValueBoxKeyDown(object sender, dynamic e)
{
if (e.KeyCode != "enter")
return;
string old;
string newValue = this.Transform(db, dbValues.SelectedIndex, fieldBox.SelectedIndex, valueBox.Text, out old);
MessageBox.Show("Value set: " + old + " to " + valueBox.Text + ".");
}
}
So this is better:
public class SomeView
{
dynamic fieldBox = null;
dynamic valueBox = null;
dynamic dbValues = null;
dynamic MessageBox = null;
private List<Person> People = new List<Person>();
private void LoadDB()
{
//Structure
string myStruct = "NAME\nAGE\nSEX\nSKILL";
string db = "John\t20\tMale\tNoob\n" +
"Joe\t20\tMale\tMedium\n" +
"Jessica\t27\tFemale\tExpert\n" +
"John\t21\tMale\tMedium";
//Load struct to combobox
string[] mbstr = myStruct.Split('\n');
for (int i = 0; i < mbstr.Length; i++)
{
fieldBox.Items.Add(mbstr[i]);
}
People.Clear();
foreach(var row in db.Split('\n'))
{
var columns = row.Split('\t');
Person p = new Person();
p.Name = columns[0];
p.Age = int.Parse(columns[1]);
p.Sex = (Person.Sexs)Enum.Parse(typeof(Person.Sexs), columns[2]);
p.SkillLevel = (Person.SkillLevels)Enum.Parse(typeof(Person.SkillLevels), columns[2]);
People.Add(p);
dbValues.Items.Add(string.Format("{0}-{1}", p.Name, p.Age);
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public enum Sexs
{
Male,
Female
}
public Sexs Sex { get; set; }
public enum SkillLevels
{
Noob,
Medium,
Expert
}
public SkillLevels SkillLevel { get; set; }
}
void ValueBoxKeyDown(object sender, dynamic e)
{
if (e.KeyCode != "enter")
return;
Person p = this.People[dbValues.SelectedIndex];
switch((int)fieldBox.SelectedIndex)
{
case 0: p.Name = valueBox.Text; break;
case 1: p.Age = int.Parse(valueBox.Text); break;
case 2: p.Sex = (Person.Sexs)Enum.Parse(typeof(Person.Sexs), valueBox.Text); break;
case 3: p.SkillLevel = (Person.SkillLevels)Enum.Parse(typeof(Person.SkillLevels), valueBox.Text); break;
default: throw new NotImplementedException();
}
MessageBox.Show("Value set: " + old + " to " + valueBox.Text + ".");
}
}
However this is still garbage, since if you have a strongly typed data set you can actually bind this to form controls without directly manipulating the item.
https://msdn.microsoft.com/en-us/library/c8aebh9k(v=vs.110).aspx
You cannot change the return-value of a method returning a string as strings are immutable. What you can do instead is the following:
string myDatabase =
"Garry\t19\tMale\tNoob\n" +
"Joe\t25\tMale\tMedium\n" +
"Gary\t33\tFemale\tExpert";
var tmp = "";
foreach(var line in myString.Split('\n')) {
tmp = tmp + Regex.Replace(line, "^.*?(?=\\t)", myReplaceText);
}
myString = tmp;
This regex will search for everything before the very first tab within every line, replaces it by "Jerry"and and concatenates every so replaced line into myString.

List Re-Order is mixing up property values across list items

I have a strange situation happening or maybe it is my misunderstanding of lists, or it is one of those cases where you look at it too long and am missing something simple.
When I re-order a list in this example, it is mixing up column values across rows in the list. Here are some pics as an example as captured during debugging.
In the below pic, first note the list ordering done on 783. Next note the ItemId value of position [0] in the list. It is 1121.
Now after just advancing from line 793 to 798, note the values of inventoryNeed after it has been assigned the value from lstInventoryNeeds[i]. Note that its ItemId value is 1336! And further, the same list entry in position [0] also changed JUST the ItemId value from 1121 to 1336! What just happened?!?!
Now if I comment out the original list re-order code on line 783 and run it again, see this pic, captured just after the inventoryNeed assignment when i = 0 just as before, but there is no mix up in the ItemId value.
Any idea why this is happening?
Here is code for this section, but not sure how useful it is taken out of context:
private ActionConfirmation<int> AllocateContainersForNeedList(List<AllocationNeedViewModel> lstInventoryNeedsOriginal, int intUserId, bool failOnShortage)
{
//Sort by this so if first alloc attempt fails for the remnant,
//then add that qty to next Need in list (if exists) and attempt allocate for full sheets
var lstInventoryNeeds = lstInventoryNeedsOriginal;
//.OrderBy(x => x.ItemId)
//.ThenByDescending(x => x.IsRemnant)
//.ToList();
ActionConfirmation<int> allocateResult = ActionConfirmation<int>.CreateSuccessConfirmation("Allocation of Containers for Needs List Successful.",1);
bool firstOfTwoNeedsForSameItem = false;
AllocationNeedViewModel inventoryNeed;
for (int i = 0; i < lstInventoryNeeds.Count; i++)
{
inventoryNeed = lstInventoryNeeds[i];
//If this is an inventory tracked item, allocate it
if (boolIsInvenTrackedItem(inventoryNeed.ItemId))
{
//Allocate the required inventory for the need just created
if (lstInventoryNeeds.Count() > i + 1)
{
firstOfTwoNeedsForSameItem = inventoryNeed.IsRemnant && (lstInventoryNeeds[i + 1].ItemId == inventoryNeed.ItemId);
}
else
{
firstOfTwoNeedsForSameItem = false;
}
allocateResult =
AllocInvenForNeed(
inventoryNeed.FacilityId,
inventoryNeed,
intUserId,
0,
0,
!firstOfTwoNeedsForSameItem
);
//Create Allocation Error
if (!allocateResult.WasSuccessful)
{
//Check if original attempt was for a Remnant
if (firstOfTwoNeedsForSameItem)
{
//Add current remnant need to the next need for this item, which will then get allocated on the next loop
lstInventoryNeeds[i + 1].QtyNeeded = lstInventoryNeeds[i + 1].QtyNeeded + inventoryNeed.QtyNeeded;
}
else
{
return allocateResult;
}
}
} //if inventory tracked item
}//for loop
return allocateResult;
}
Here is a MCVE, but I can't replicate the problem...but maybe I'm missing some key element that would have an impact
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var lstInventoryNeedsOriginal = new List<AllocNeedVM>();
int b = 5;
for (int a = 0; a <= b; a++)
{
int c = b - a;
var allocNeed = new AllocNeedVM()
{
ItemId = c,
ItemDesc = "Item " + c.ToString(),
IsRemnant = false
};
lstInventoryNeedsOriginal.Add(allocNeed);
}
AllocNeedVM inventoryNeed;
Console.WriteLine("List before sort.");
for (int i = 0; i < lstInventoryNeedsOriginal.Count; i++)
{
inventoryNeed = lstInventoryNeedsOriginal[i];
Console.WriteLine("{0}, {1}, {2}", inventoryNeed.ItemId, inventoryNeed.ItemDesc, inventoryNeed.IsRemnant);
}
var lstInventoryNeeds = lstInventoryNeedsOriginal
.OrderBy(x => x.ItemId)
.ThenByDescending(x => x.IsRemnant)
.ToList();
Console.WriteLine("List after sort.");
for (int i = 0; i < lstInventoryNeeds.Count; i++)
{
inventoryNeed = lstInventoryNeeds[i];
Console.WriteLine("{0}, {1}, {2}", inventoryNeed.ItemId, inventoryNeed.ItemDesc, inventoryNeed.IsRemnant);
}
Console.ReadLine();
}
}
public class AllocNeedVM
{
public int ItemId { get; set; }
public string ItemDesc { get; set; }
public bool IsRemnant { get; set; }
}
}

Split string into class

I have an array which contains following values:
str[0]= "MeterNr 29202"
str[1]="- 20111101: position 61699 (Previous calculation) "
str[2]="- 20111201: position 68590 (Calculation) consumption 6891 kWh"
str[3]="- 20111101: position 75019 (Previous calculation) "
str[4]="MeterNr 50273"
str[5]="- 20111101: position 18103 (Previous reading) "
str[6]="- 20111201: position 19072 (Calculation) consumption 969 kWh "
I want to split the rows in logical order so that I can store them in following Reading class. I have problems with spliting the values. Everything in brackets () is ItemDescription.
I will be thankful for the quick answer.
public class Reading
{
public string MeterNr { get; set; }
public string ItemDescription { get; set; }
public string Date { get; set; }
public string Position { get; set; }
public string Consumption { get; set; }
}
You should parse the values one by one.
If you have a string, which starts with "MeterNr", you should save it as currentMeterNumber and parse the values further.
Otherwise, you can parse the values with Regex:
var dateRegex = new Regex(#"(?<=-\s)(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})");
var positionRegex = new Regex(#"(?<=position\s+)(\d+)");
var descriptionRegex = new Regex(#"(?<=\()(?<description>[^)]+)(?=\))");
var consuptionRegex = new Regex(#"(?<=consumption\s+)(?<consumption>(?<consumtionValue>\d+)\s(?<consumptionUom>\w+))");
I hope, you would be able to create the final algorithm, as well as understand how each of those expressions works. A final point could be to combine them all into single Regex. You should do it yourself to enhance your skills.
P.S.: There are a lot of tutorials in Internet.
I would just use a for loop and string indexes etc, but then I am a bit simple like that! Not sure of your data (i.e. if things might be missing) but this would work on the data you have posted...
var readings = new List<Reading>();
int meterNrLength = "MeterNr".Length;
int positionLength = "position".Length;
int consumptionLength = "consumption".Length;
string meterNr = null;
foreach(var s in str)
{
int meterNrIndex = s.IndexOf("MeterNr",
StringComparison.OrdinalIgnoreCase);
if (meterNrIndex != -1)
{
meterNr = s.Substring(meterNrIndex + meterNrLength).Trim();
continue;
}
var reading = new Reading {MeterNr = meterNr};
string rest = s.Substring(0, s.IndexOf(':'));
reading.Date = rest.Substring(1).Trim();
rest = s.Substring(s.IndexOf("position") + positionLength);
int bracketIndex = rest.IndexOf('(');
reading.Position = rest.Substring(0, bracketIndex).Trim();
rest = rest.Substring(bracketIndex + 1);
reading.ItemDescription = rest.Substring(0, rest.IndexOf(")"));
int consumptionIndex = rest.IndexOf("consumption",
StringComparison.OrdinalIgnoreCase);
if (consumptionIndex != -1)
{
reading.Consumption = rest.Substring(consumptionIndex + consumptionLength).Trim();
}
readings.Add(reading);
}
public static List<Reading> Parser(this string[] str)
{
List<Reading> result = new List<Reading>();
string meterNr = "";
Reading reading;
foreach (string s in str)
{
MatchCollection mc = Regex.Matches(s, "\\d+|\\((.*?)\\)");
if (mc.Count == 1)
{
meterNr = mc[0].Value;
continue;
}
reading = new Reading()
{
MeterNr = meterNr,
Date = mc[0].Value,
Position = mc[1].Value,
ItemDescription = mc[2].Value.TrimStart('(').TrimEnd(')')
};
if (mc.Count == 4)
reading.Consumption = mc[3].Value;
result.Add(reading);
}
return result;
}

Categories