Hierarchical list based on two different properties of same List - c#

I have a list of 'quests' with a quest that is 'granted' when one 'ends'. The quests are not stored in sequential order so I'm attempting to find two things.
class quests
{
public string questGrantID { get; set; }
public string questEndID { get; set; }
}
Example
+--------------+--------------+
| grants | ends |
+--------------+--------------+
| quest234 | quest567 |
| quest987 | quest234 |
| quest654 | quest987 |
+--------------+--------------+
Parent Quests: In this example I would know the 'Parent' quest is quest567 because the parent is found under questEndID but not under questGrantID.
Children Quests: In this example, after quest567 is completed, the user is granted quest234. When quest quest234 ends, quest987 is granted and so on.
I don't know where to start, i've looked up example of joining two separate list, not the same. I assume this will be two different functions, one to find the parents and the other finding the children. From there i will create a new list.
Example
+--------------+--------------+
| order | quest |
+--------------+--------------+
| 1 | quest567 |
| 2 | quest234 |
| 3 | quest987 |
| 4 | quest654 |
+--------------+--------------+

Finding the parent quests is easy, simply get a list of IDs not in any Grant.
Using a convenient extension method:
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source) => new HashSet<T>(source);
You can gather all the GrantIDs and find the EndIDs that aren't there:
var grants = questsList.Select(q => q.questGrantID).ToHashSet();
var parents = questsList.Select(q => q.questEndID).Where(q => !grants.Contains(q));
Now since your chain is recursive, you need a loop to follow the chain. Write another extension method to produce the quest chain from a starting point:
public static IEnumerable<string> questChain(this List<quests> allQuests, string curQuestID) {
yield return curQuestID;
var nextQuest = allQuests.ToDictionary(q => q.questEndID, q => q.questGrantID);
for (; nextQuest.TryGetValue(curQuestID, out var nextQuestID); curQuestID = nextQuestID)
yield return nextQuestID;
}
Now you can call that on all the parents to get all the chains:
var questChains = parents.Select(pq => questsList.questChain(pq));
Now if you really want the order,quest pair, you can number each chain:
var orderedQuests = questChains.Select(qc => qc.Select((quest, i) => new { order = i+1, quest } ));
If you want the numbering to be continuous across the chains, you will need to track it outside the query:
var curOrder = 1;
var orderedQuestsContinuous = questChains.Select(qc => qc.Select(quest => new { order = curOrder++, quest }));

Related

FitNesse / FitSharp - Read columns of ColumnFixture dynamically

I am using the FitNesse / FitSharp (c#) for testing purposes.
I can create normal fixture like ColumnFixtures, RowFixtures, DoFixtures etc. but not I am looking for a way to read columns and bind them dynamically.
The reason for this is, I still already have a huge amount of Pojo objects in my own library and don't want to repeat all class members again. Therefor i am searching for a way to handle column dynamically.
e.g.
!|Create| pojoType | record | pojoName |
|Name | LastName | Address| Misc |
| a | b | c | d |
public class DynamicHandling : DoFixture () {
public void CreateRecord(string type, string name) {
var clazz = GetClazzOfType();
var headers = GetHeadersOfColumn();
var values = GetValuesOfColumn();
var pojo = DoBindingAndAssignValues(headers, rows, clazz);
// ... Continue with whatever e.g. ...
var name = pojo.Name;
var lastName = pojo.LastName;
var address = pojo.Address;
address.split(';') ...
}
}
Any idea ?
Take a look at the source code for the Compute fixture (https://fitsharp.github.io/Fit/ComputeFixture.html) and see if it helps.
You can write a fixture that processes cells dynamically like this:
public class MyFixture: Interpreter {
public void Interpret(CellProcessor processor, Tree<Cell> table) {
new Traverse<Cell>()
.Rows.Header(row => FunctionThatDoesSomethingWithTheHeaderRow(row))
.Rows.Rest(row => FunctionThatDoesSomethingWithEachSubsequentRow(row))
.VisitTable(table);
}
...
}
There's other sets of rows you can traverse - check out the Traverse source code.

LinqToExcel parsing pivoted data

I've been trying to parse an excel file using the LinqToExcel library. My excel file has the following "design":
Property1 | Property2 | HasExtraProperty1 | HasExtraProperty2 | HasExtraProperty3
------------|---------------|-----------------------|-----------------------|-------------------
foo | bar | yes | yes | no
barfoo | foobar | no | no | yes
barbar | foofoo | no | yes | no
An abstraction of my model looks like this:
class MyModel
{
List<ExtraProperties> extraProperties;
String property1;
String property2;
}
I used the mappings from the library to easily map the (in this example) String properties to the columns. This all works fluently, but now I'm stuck parsing the other properties. Only the the extra properties with a "yes" should be added to the list. Any ideas on how to solve this with a linq query?
Note 1: For future-proofness, the number of extra properties should be able to vary.
Note 2: I've considered using another library, but I'm already using LinqToExcel somewhere in my project, and I'm trying to keep the dependencies at a minimum.
Seems like the easiest solution was to abandon the convenient mapping provided by LinqToExcel, and just looping through every columnname/row.
IExcelQueryFactory fact = new ExcelQueryFactory(path);
var query = from r in fact.Worksheet(0)
select r;
IList<MyModel> models = new List<MyModel>();
foreach(var row in query){
MyModel m = new MyModel();
foreach(String colName in MyColMapping.Keys){
p.GetType().GetProperty(colName).SetValue(p, row[ColMapping[colName]]);
}
foreach(ExtraProperty p in PMapping.Keys){
if(row[PMapping[p]].Equals("yes"))
m.ExtraProperties.Add(p);
}
models.add(m);
}
Note: ColMapping is a dictionary which maps names of excel-columns with model-properties. PMapping is a dictionary which maps excel-columns with the right object of the extra properties.

How to reset an object int value when an intermediate element is remove from list

I got a list with objects that have an attribute "serie" that save the order of elements:
---------------------------------
| **Element** |**Serie** |
---------------------------------
| Object1 | 1 |
---------------------------------
| Object2 | 2 |
---------------------------------
| Object3 | 3 |
---------------------------------
How can i get that, if i remove element 2, the atribute serie of my object 3 change to 2, i meant, reset the value of serie of all the elements after the element removed.
Any help will be much apreciated.
You will have to manually loop over the list and modify the property of the objects, setting its value on each item to be equal to the item's index.
If you know the index of the object that was removed then you can start looping from that point onwards, since nothing will have changed for the objects that come earlier.
How about:
public class Object
{
public int Serie;
}
Then:
var list = new List<Object>();
list.Add(new Object { Serie = 1 });
list.Add(new Object { Serie = 2 });
list.Add(new Object { Serie = 3 });
list.RemoveAt(1);
int i = 1;
foreach (Object obj in list)
{
obj.Serie = i;
i++;
}

Oracle linq to entities query returning duplicated columns

I'm trying to query an Oracle DB (version 11.2.0.2.0) in a project that uses ADO.NET, compiled at .NET 4 (I would compile at .NET 4.5 if Windows XP was compatible with it), and uses linq to entities to perform the query. I'm also using Oracle Developer Tools for Visual Studio and ODP.NET version 11.2.0.3.20. However, whenever the query is performed in the application, I get back a list of objects with incorrect data. What I mean by incorrect data is this: I have 5 properties in the entity object and two of those properties are not set as entity keys. The two properties that ARE NOT set as entity keys contain the same data for all records returned...but when I manually do a query on the DB with a DB query client, I get different values in those columns for each record!
Here's the auto generated code that I'm getting (using DBContext but I've verified that this happens with ObjectContext too):
public partial class EntityObj
{
public string EntityKey1 { get; set; }
public string EntityKey2 { get; set; }
public string EntityKey3 { get; set; }
public Nullable<decimal> NonEntityKey1 { get; set; }
public string NonEntityKey2 { get; set; }
}
Here's my linq to entities code:
using (Entities context = new Entities())
{
string formattedStr = Decimal.Parse(str).ToString();
var objs = (from obj in context.EntityObjs
where obj.Number == formattedStr
orderby obj.EntityKey3 , obj.NonEntityKey2, obj.NonEntityKey1
select obj);
// Process results...
}
Here is an example of the result set that I get when I manually do the query:
| EntityKey1 | EntityKey2 | EntityKey3 | NonEntityKey1 | NonEntityKey2 |
----------------------------------------------------------------------------------
| Val1.1 | Val1.2 | Val1.3 | 1 | Val1.4 |
----------------------------------------------------------------------------------
| Val2.1 | Val2.2 | Val2.3 | 2 | Val2.4 |
----------------------------------------------------------------------------------
| Val3.1 | Val3.2 | Val3.3 | 3 | Val3.4 |
----------------------------------------------------------------------------------
| Val4.1 | Val4.2 | Val4.3 | 4 | Val4.4 |
Here is an example of the result set that I get when I use the linq to entities:
| EntityKey1 | EntityKey2 | EntityKey3 | NonEntityKey1 | NonEntityKey2 |
----------------------------------------------------------------------------------
| Val1.1 | Val1.2 | Val1.3 | 1 | Val1.4 |
----------------------------------------------------------------------------------
| Val2.1 | Val2.2 | Val2.3 | 1 | Val1.4 |
----------------------------------------------------------------------------------
| Val3.1 | Val3.2 | Val3.3 | 1 | Val1.4 |
----------------------------------------------------------------------------------
| Val4.1 | Val4.2 | Val4.3 | 1 | Val1.4 |
Why am I seeing the results that I'm seeing and how do I fix it to return the correct data without making the non entity key fields entity keys? (They can't be keys cause they are nullable)
EDIT:
I should also point out that when I do the following query I don't see the same issues...but I really would like things to work as I've stated before.
using (Entities context = new Entities())
{
string formattedStr = Decimal.Parse(str).ToString();
var objs = (from obj in context.EntityObjs
where obj.Number == formattedStr
orderby obj.EntityKey3 , obj.NonEntityKey2, obj.NonEntityKey1
select new
{
EntityKey1 = obj.EntityKey1,
EntityKey2 = obj.EntityKey2,
EntityKey3 = obj.EntityKey3,
NonEntityKey1 = obj.NonEntityKey1,
NonEntityKey2 = obj.NonEntityKey2
});
// Process results...
}
I guess the problem could be because you might not have a good primary key in your entity object. Take a look at the solution given here.. This might solve your problem if this is your issue.

how to compare current row with the previous row in the same table

How to compare everytime, the current record with the previous record in the same table using MySQL C# in MVC3.0.
This is my table
Historytable:
id | projid| task | name | description | date | type
----|-------| ----- | -------------- |------------ | -------| ---------
1 | 1 | sys21 | validation | validating user | 1-5-12 | created
2 | 1 | sys21 | bug tracking | background bug | 23-7-12 | updated
| | | | tracking | |
3 | 1 | sys21 | bug tracking | bug reporting | 30-8-12 | updated
4 | 1 | sys21 | bugs | bug reporting | 12-9-12 | updated
----------------------------------------------------------------------------------
now i want the result such that compare the record of type updated with the previous record in order to show the previous record as the previous history and record obtained by comparing with the previous record and display only the updated fields as the current history.
now depending upon the projid retrieve the history.
and my view look like the below:
previous history current history
---------------- ---------------
type: created
name: validation
description: validating user
--------------------------------------------------------------
type: created updated
name validation bug tracking
description: validating user background bug tracking
--------------------------------------------------------------------
type: updated updated
name: bug tracking bug report
description: background bug tracking bug reporting
----------------------------------------------------------------
type: updated updated
name: bug tracking -
Description: background bug tracking bug reporting
------------------------------------------------------------------------
type: updated updated
name: bug tracking bugs
Description: bug reporting -
I am expecting the above output, any one plz help me out from the situation,
any king of sugesions will be accepted...
Thankyou,
I am not sure I understood you correctly but you could approach this with the following logic:
Get the rows that represent the history of an item and order by date descending
Get the first row from above as the last change
Get the second row from 1. as the previous to last change
Compare the data
Here's a potential approach for this (using Linq):
var history = db.History.Where(item => item.ProjId == 1)
.OrderByDescending(item => item.Date);
var lastChange = history.First();
var previousChange = history.Skip(1).First();
Now you need to send the above rows to your comparison method. If you want to highlight the changes, you can iterate through properties of the rows and compare values for same properties like this:
private IEnumerable<Tuple<string, object, object>> GetChangesBetweenRows(History row1, History row2)
{
var result = new List<Tuple<string, object, object>>();
var properties = lastChange.GetType().GetProperties(); // both rows are of the same type
foreach(var propInfo in properties)
{
var obj1 = propInfo.GetValue(lastChange, null);
var obj2 = propInfo.GetValue(previousChange, null);
if(obj1 != obj2)
result.Add(Tuple.Create(propInfo.Name, obj1, obj2));
}
return result;
}
EDIT
Given the method above, you can iterate through a collection of history rows and get differences between any of two rows in the collection:
static void Main(string[] args)
{
var history = db.History.Where(item => item.ProjId == 1)
.OrderBy(item => item.Date)
.ToArray();
for(int i=1; i<history.Length; i++)
{
var diff = GetChangesBetweenRows(history[i-1], history[i]);
DisplayDifferences(diff);
}
}
static void DisplayDifferences(IEnumerable<Tuple<string, object, object>> diff)
{
foreach(var tuple in diff)
{
Console.WriteLine("Property: {0}. Object1: {1}, Object2: {2}",tuple.Item1, tuple.Item2, tuple.Item3);
}
}

Categories

Resources