Match algorithm - c#

I am unsure how take data from an IEnum object and dump it to a Dictionary and/or List, and would appreciate any guidance.
I'm working on a program that sorts through a collection of data pulled from SQL DB. I'm using Enterprise Library 5 (Data Access Application Block). So far there is an adapter class that will create an instance of the DB, map the query results to appropriate fields (Namely: First, middle, last names, DoB, and an ID), and it has two methods of type IEnumerable that will pass the SQL statement. I am unsure of how the the return IEnum object looks like. One method will return a list of offenders and another will return a list of all the records based on DoB:
public IEnumerable<Person> GetOffenders()
{
var people =
_db.ExecuteSqlStringAccessor<Person>(#"SELECT pm.Local_ID, pm.First_Name, pm.Last_Name, pm.Middle_Name, pm.DOB
FROM Person_Main pm ", _personRowMapper);
return people;
}
In another class that will hold the matching logic, I am trying to "dump" the contents of the getOffenders() which was defined in the adapter class, the idea is iterate over the two lists (offenders and all records based on DoB). I'm assuming the a good route would be to use a Dictionary to hold the results from getOffenders(). So far I've got this test code, which only checks to see if the connection to the DB is successful and retrieves a row of dummy data I entered:
PersonAdapter personAdapter = new PersonAdapter();
private Dictionary<String, List<Person>> testDictionary = new Dictionary<String, List<Person>>();
public void Test1()
{
var offenders = personAdapter.GetOffenders();
var pList = new List<Person>();
// Test to see if GetOffenders is returning data correctly
foreach (var variable in offenders)
{
var fName = variable.FirstName;
var mName = variable.MiddleName;
var lName = variable.LastName;
var lId = variable.LocalId;
Console.WriteLine(variable.FirstName + " " + variable.MiddleName + " " +
variable.LastName + " " + variable.LocalId);
Console.ReadLine();
}

An IEnumerable implementation only returns one item at a time. If you want to transfer those to a static collection you will need to loop through the IEnumerable collection and then do a List<Person>.Add(item).
foreach(var item in offenders)
{
pList.Add(item);
}
Then you can use your pList collection as a normal List<> to then add to your testDictionary field.
testDictionary.Add("some_string_key", pList);

Related

Shelling an item from a list item

I am automating some website and I got stuck on such a case. I have a list created, everything is great for me, it has 24 elements. These are products from the store, containing their picture, name, price, etc. But now I need to take two things from the first element and display in the console, namely name and price. Is anyone able to suggest something? I sit and thinks but nothing comes out. All I managed to do was send everything for 1 item.
I tried resolve that with some Linq but without success.
public List<string> ListOfElements()
{
var elements = new List<string>();
IReadOnlyCollection<IWebElement> listElements = _driver.FindElements(By.CssSelector(".category-list div[class='cat-prod-row js_category-list-item js_clickHashData js_man-track-event ']");
foreach (IWebElement element in listElements)
{
elements.Add(element.Text);
}
return elements;
}
public void DisplayFirstElement()
{
var firstElement = ListOfElements();
Console.WriteLine(firstElement[0]);
}
I want get name and price of first element and then assert that price for that is greater than 10.
You´re flattening all the elements properties into a single collection of strings. Thus you´re losing any relationship between those strings. It´s hard to say what the 22rd element within thhat list actually is: is it a price? A name? Something completey different? To which item does it actually belong?
Instead you should just return a list of entities and then print the properties of the very first entitity:
public List<IWebElement> ListOfElements()
{
var elements = new List<string>();
return listElements = _driver.FindElements(By.CssSelector(".category-list div[class='cat-prod-row js_category-list-item js_clickHashData js_man-track-event ']");
}
public void DisplayFirstElement()
{
var allElements = ListOfElements();
var firstElement = allElements.First();
Console.WriteLine("FirstName: " + firstElement.Name + " Price: " + firstElement.Price);
}
Of course this assumes your IWebElement has a Name- and a Price-property.

SSIS Script Component Input0Buffer method no GetName()?

I am looking for a way to obtain my property names in a SSIS data flow task Script Component. I have been searching high and low only finding this. I have been trying to get this code to work, but I am too novice to understand what is happening here and I don't feel it is explained very well(no offense).
The source before this component is using a SQL query joining two tables. Inside the component, I would like to compare column to column. Then call an update method I created to use SqlConnection to perform the update.
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
if (Row.TableALastName != Row.TableBLastName)
// Call the update method if the last name did not match.
this.UpdateRecord("TableBLastName", Row.TableALastName.ToString(), Row.TableAAssociateId.ToString());
}
}
private void UpdateRecord(string columnName, string change, string associateId)
{
SqlConnection sqlConnection;
sqlConnection = new SqlConnection(this.Variables.Connection);
string updateQuery = "UPDATE [SomeDataBase].[dbo].[TableB] SET " + columnName + " = " + change + " WHERE [Associate_ID] = " + associateId;
using (SqlCommand cmd2 = new SqlCommand(updateQuery, sqlConnection))
{
sqlConnection.Open();
cmd2.ExecuteNonQuery();
sqlConnection.Close();
}
}
I would like to somehow get the PropertyName of Row.TableBLastName instead of having to hard code "TableBLastName" for each test I am doing, which will be a lot.
The problem is that the input buffer class does not have Property.GetName() This also means I can't add a method to the class to get the property names, as it is regenerated each run.
public Input0_ProcessInputRow(Input0Buffer Row)
{
Dictionary<string, List<string>> list = new Dictionary<string, List<string>>();
List<string> propertyList = new List<string>();
Type myType = typeof(Input0Buffer);
PropertyInfo[] allPropInfo = myType.GetProperties();
List<PropertyInfo> SqlPropInfo = allPropInfo.Where(x => !x.Name.Contains("AM_")).ToList();
// Loop through all the Sql Property Info so those without AM_
for (int i = 0; i < SqlPropInfo.Count(); i++)
{
List<string> group = new List<string>();
foreach (var propInfo in allPropInfo)
{
if (propInfo.Name.Contains(SqlPropInfo[i].Name))
{
// Group the values based on the property
// ex. All last names are grouped.
group.Add(propInfo.GetValue(Row, null).ToString());
}
}
// The Key is the Sql's Property Name.
list.Add(SqlPropInfo[i].Name, group);
}
foreach (var item in list)
{
// Do a check if there are two values in both SQL and Oracle.
if (item.Value.Count >= 2)
{
if (item.Value.Count() != item.Value.Distinct().Count())
{
// Duplicates exist do nothing.
}
else
{
// The values are different so update the value[0]. which is the SQL Value.
UpdateRecord(item.Key, item.Value[0], Row.AssociateId);
}
}
}
}
I separated the values from the two tables so there are two lists values from TableA and TableB. You can prefix the values from TableA with "AM_" or something distinct so you can use reflection to to get the properties with and without the prefix and find out which values belong to which table. Then I just loop through the properties and group the values with the properties from the target value (so those without the prefix "AM_") I then loop through the grouped list and compare the two values and if it's different, update TableA with the TableB values to match them
You are already in SSIS so I will propose using that (no matter how quick I usually jump to C# to solve problems)
This is a classic conditional split scenario:
Do your test then run the results into a SQL Update statement.

Return entire collection from MongoDB

using the official mongo / c# drivers - what is the best way of returning an entire collection, and what is the best way of storing the data? I've seen some examples of iterating over a collection and returning a particular value, like this:
var collection = db.getCollection("users").findAll();
foreach (var value in collection){
value = collection["key"];
...
}
but what if I don't know the key names - and I just want to return the collection?
You dont need to know the key names when returning a collection.
public static void ReadCollectionDataUsingBson(string collectionName, string databaseName)
{
MongoDatabase database = CreateDatabase(databaseName);
MongoCollection<BsonDocument> collection = database.GetCollection<BsonDocument>(collectionName);
foreach (BsonDocument document in collection.FindAll())
{
foreach (string name in document.Names)
{
BsonElement element = document.GetElement(name);
Console.WriteLine("{0}: {1}", name, element.Value);
}
Console.WriteLine();
}
}
Note: CreateDatabase() function is user defined, so i have just shown you the required code over here.

Arrays/Array Lists

I am fairly new to C#
I am trying to retrieve some information from an external data source and store it in array, once it is in an array I wish to sort it by time.
I know how to do this for just one column in a row, however the information I require has multiple columns.
For example:
foreach (Appointment Appoint in fapts)
{
// Store Appoint.Subject, Appoint.Start, Appoint.Organiser.Name.ToString(), Appoint.Location in an array
}
// Sort my array by Appoint.Start
foreach ( item in myNewArray )
{
//print out Appoint.Subject - Appoint.Start, Appoint.Organiser.Name.ToString() and Appoint.location
}
Many thanks for your help.
EDIT:
I have multiple data sources which pull in this:
foreach (Appointment Appoint in fapts)
{
// Store Appoint.Subject, Appoint.Start, Appoint.Organiser.Name.ToString(), Appoint.Location in an array
}
Hence the need to sort the items in a new array, I know this isn't very efficent but there is no way of getting the information I need in any other way.
You can sort a list using the LINQ sorting operators OrderBy and ThenBy, as shown below.
using System.Linq;
and then...
var appointments = new List<Appointment>();
var sortedAppointments = list.OrderBy(l => l.Subject).ThenBy(l => l.Name).ToList();
This will create a new list of appointments, sorted by subject and then by name.
It's unclear what your final aim is but:
Use a generic List instead of an array:
See this SO question for more information as to why using a List is prefered.
List<Appointment> appointments = new List<Appointment>();
foreach (Appointment Appoint in fapts)
{
appointments.Add(Appoint);
}
foreach (var item in appointments)
{
Console.WriteLine(item.Subject);
Console.WriteLine(item.Foo);
// Here you could override ToString() on Appointment to print eveything in one Console.WriteLine
}
If the aim of your code is to order by time, try the following:
var sortedAppointments = fapts.OrderBy(a => a.Start); // assuming Start is a DateTime property of `Appointment`.
Consider a Dictionary Object instead of an array if the data is conceptually one row multiple columns.
foreach(KeyValuePair<string, string> entry in MyDic)
{
// do something with entry.Value or entry.Key
}
You already have a list of objects in fpts, sort that list itself:
fpts.OrderBy(x => x.Subject).ThenBy(x => x.Location).ToList();
LINQ is your friend here.
fapts appears to already be a collection so you could just operate on it.
var myNewArray = fapts.OrderBy(Appoint => Appoint.Start).ToArray()
I've used the ToArray() call to force immediate evaluation and means that myNewArray is already sorted so that if you use it more than once you don't have to re-evaluate the sort.
Alternatively if you are only using this once you can just as easily miss the ToArray() portion out and then execution of the sort will be deferred until you try and enumerate through myNewArray.
This solution puts the source objects into the array, but if you are just wanting to store the specific fields you mention then you will need to use a select. You have two choices for the array item type, you can either use an anonymous class which provides difficulties if you are returning this array from a function or define a class.
For anonymous:
var myNewArray = fapts.OrderBy(Appoint => Appoint.Start)
.Select(Appoint => new {
Start = Appoint.Start,
Organiser = Appoint.Organiser.Name.ToString(),
Location = Appoint.Location
}).ToArray();
For named class assuming class is MyClass:
var myNewArray = fapts.OrderBy(Appoint => Appoint.Start)
.Select(Appoint => new MyClass {
Start = Appoint.Start,
Organiser = Appoint.Organiser.Name.ToString(),
Location = Appoint.Location
}).ToArray();
You have a wide range of options. The 2 most common are:
1) Create a class, then define an array or list of that class, and populate that
2) Create a structure that matches the data format and create an array or list of that
Of course, you could put the data into an XML format or dataset, but that's probably more work than you need.
public List<foo> appointments = new List<foo>();
public struct foo
{
public string subject ;
public DateTime start ;
public string name ;
public string location ;
}
public void foo1()
{
// parse the file
while (!File.eof())
{
// Read the next line...
var myRecord = new foo() ;
myRecord.subject = data.subject ;
myRecord.start = data.Start ;
myRecord.name = data.Name ;
//...
appointments.Add(myRecord);
}
}
Enjoy
(Since I can't comment and reply to the comment - it wasn't clear if he had a class, etc. or was just showing us what he wanted to do. I assumed it was just for demonstration purposes since there wasn't any info as to how the data was being read. If he could already put it into a class, than the first answer applied anyway. I just tossed the last 2 in there because they were options for getting the data first.)

Best way of building a collection of unique ID's as well as their counts

I've looked into various different ways of array's, arraylist's, dictionaries... but as I'm used to PHP I'm not entirely sure on the best way I could collect the following information.
My program loops through each user, and if their is a location ID, I want to add that to some sort of collection / array. It's expected that different users will have the same location ID.
If the location ID is the same, I need to increase an integer of how many occurrence for that location ID.
Example:
User1 - Location1
User2 - Location3
User3 - Location3
Location1 = 1
Location3 = 2
Also I need to somehow append each user ID to this collection. So Location3 / 2 occurrences / user2/user3
I've been trying to figure out the best way of doing this for about two hours now, and all the different methods of multidimensional arrays, arraylists, dictionaries is all a little confusing as it all seems abstract to my PHP knowledge. I think C# handles arrays in an entirely different way.
Essentially, the collection with unique location ID's / occurrences / and users collection needs to be stored in something that can be passed to somewhere else in my program as an argument.
I've made a PHP script which does exactly what I'm after
foreach($call["data"] as $v)
{
// Foreach USER ($v containing their unique ID and location ID.)
$user_id = $v["id"];
$location_id = $v["location"]["id"];
// This adds the location ID as the key within the array, followed by every user who has it. I don't need a count in this case, as I could just count the number of users.
$collection[$location_id][$user_id] = null;
}
This in return creates this array when printed using print_r
[106078429431815] => Array
(
[620790873] =>
[626276302] =>
[100000152470577] =>
)
(Small part of the output). - Added PHP Example.
Anyone know how I can get C# to collect the same information in the same way my PHP array does?
using System.Linq;
var grouppingByLocation = users.GroupBy(u => u.LocationID);
foreach (var g in grouppingByLocation)
{
Console.WriteLine("Location id: {0}", g.Key);
foreach (var u in g)
{
Console.WriteLine("User id: {0}", u.ID);
}
}
See Enumerable.GroupBy() for more details.
This is an Extension Method over IEnumerable<T> interface implemented by any built-in collection (such as Array T[], List<T>, Dictionary<K,V>, etc.) which accepts a lambda expression pointing to a property of class collection of which you're grouping by.
If you want to build the list looping through initial data, you can create object like this:
var list = new Dictionary<int, Tuple<int, List<int>>();
And fill it in the loop
if(list[locationID]==null) list[locationID] = Tuple.Create(0,new List<int>());
//..
list[locationId].Item1++; // counter
list[locationId].Item2.Add(userId); //list of users
Create an object to hold each item of data.
public Class Model{
public int LocationId {get;set;}
public int Occurences{get;set;}
public IList<User> Users{get;set;}
}
Initialize the container as a list of items.
var container = List<Model>();
Process you list of users.
foreach(var user in userList){
var model = container.SingleOrDefault(x=> x.LocationId == user.LocationId);
if(model != null){
model.Users.Add(user);
} else{
model = new Model{
model.Users = new List<User>.Add(user);
model.LocationId = user.LocationId;
container.Add(model)
}
model.Occruences ++;
}
}
var byLocation = users.Where(u => !string.IsNullOrEmpty(u.Location))
.GroupBy(u => u.Location);
var stats = byLocation.Select(l => string.Format("{0} / {1} occurrences / {2}",
l.Key, l.Count(), string.Join("/", l.Select(u => u.User)));
// And just to print the result
foreach (var location in stats)
Console.WriteLine(location);

Categories