Build groups from a directed graph dictionary - recursion

Given a dictionary of a directed graph, representing nested groups and their members, return all the users for a given group.
example-
Hashmap-
key|Values
Group1- [ Group3, Group5, User8, User2]
Group2 -[ Group1, User9]
Group3 -[ Group4, User5]
Group4 -[ User1, User3]
Group5 -[ User4, User7]
O/P should be :
group1 : [User1, User3,User5, User4, User7,User8, User2]
group2 : [User1, User3,User5, User6, User7,User8, User9]
group3: [User1, User3,User5]
group4: [User1, User3]
group5: [User4, User7]
I have tried in various way for example a recursive function, but I just ended scratching my head.
public static void main(String[] args) {
HashMap<String, List<String>> hmap = new HashMap<String,List<String>>();
List<String> l1 = new ArrayList<String>();
List<String> l2 = new ArrayList<String>();
List<String> l3 = new ArrayList<String>();
List<String> l4 = new ArrayList<String>();
List<String> l5 = new ArrayList<String>();
l1.add("group3"); l1.add("group5"); l1.add("user8"); l1.add("user2");
l2.add("group1"); l2.add("user9");
l3.add("group4"); l3.add("user5");
l4.add("user1"); l4.add("user3");
l5.add("user4"); l5.add("user9");
hmap.put("group1",l1);
hmap.put("group2",l2);
hmap.put("group3",l3);
hmap.put("group4",l4);
System.out.println(hmap);
flatten(hmap);
}
public static void flatten(HashMap<String, List<String>> hmap){
ArrayList<String> groups = new ArrayList<String>();
for(Entry<String,List<String>> entryset : hmap.entrySet()){
groups.add(entryset.getKey());
}
System.out.println(groups);
for(Entry<String,List<String>> entryset : hmap.entrySet()){
String s1 = entryset.getKey();
//HashSet<String> set1 = new HashSet<String>();
ArrayList<String> values = new ArrayList<String>();
values.addAll(entryset.getValue());
}

Here is one way to do it using Scala:
def run(): Unit =
{
/* Simply initializing the given data into User and Group classes */
val (u1, u2, u3, u4) = (new User("u1"), new User("u2"), new User("u3"), new User("u4"))
val (u5, u6, u7, u8, u9) = (new User("u5"), new User("u6"), new User("u7"), new User("u8"), new User("u9"))
val g5 = new Group(List(u4, u7))
val g4 = new Group(List(u1, u3))
val g3 = new Group(List(g4, u5))
val g1 = new Group(List(g3, g5, u8, u2))
val g2 = new Group(List(g1, u9))
/* Put the groups into a list */
var groups = List(g1, g2, g3, g4, g5)
/* Map/loop over each group, calling `resolveItems` on each */
groups = groups.map{_.resolveItems}
/* Print out each of the resolved groups */
groups.foreach{println}
}
/* A simple class representing the Group entity */
case class Group(var items: List[Any])
{
/*
Returns a new group by recursively resolving the items
in this group into only users
*/
def resolveItems: Group =
{
new Group(this.items.map{
// If the item is a group, resolve it into users
case g: Group => g.resolveItems
// If the item is a user, just move along
case u: User => u
}.distinct)
}
/* Override to string for pretty printing */
override
def toString: String = items.mkString(", ")
}
/* Simply class representing the user entity */
case class User(val name: String)
{
override
def toString : String = name
}
Output:
u1, u3, u5, u4, u7, u8, u2
u1, u3, u5, u4, u7, u8, u2, u9
u1, u3, u5
u1, u3
u4, u7

Related

is there a way to get rid of DTO

I am using Entity Framework. I have the following query in which I get data using two tables Application and Employee connected by a foreign key EmployeeID in Application Table. The tables have 1-1 relationship .
Is there a way to simplify the following code and get rid of the DTO Employee1
which is the same as auto generated Employee class
public List<Employee1> GetApplicant(int ApplicationID)
{
var context = new FPSDB_newEntities();
var data = (from a in context.Applications
join e in context.Employees on a.EmployeeID equals e.EmployeeID
where
(
a.ApplicationID == ApplicationID
)
select new Employee1
{
EmployeeID = e.EmployeeID,
SecondEmail = e.SecondEmail,
EmailID = e.EmailID,
Title = e.Title,
Name = e.Name,
Rank = e.Rank,
POBox = e.POBox,
Phone = e.Phone,
JoinDate = e.JoinDate,
Status = e.Status,
DepartmentID = e.DepartmentID.Value,
NameString = e.NameString,
Department = e.Department,
ParentDept = e.ParentDept,
DepartmentAr = e.DepartmentAr,
NameAr = e.NameAr,
NameStringAr = e.NameStringAr,
TitleAr = e.TitleAr
}).ToList();
return data;
}
If you need to return list of Employees, just select e which refers to Employee and don't use Employee1 as a DTO.
public List<Employee> GetApplicant(int ApplicationID)
{
var context = new FPSDB_newEntities();
var data = (from a in context.Applications
join e in context.Employees on a.EmployeeID equals e.EmployeeID
where
(
a.ApplicationID == ApplicationID
)
select e).ToList();
return data;
}
Another way is this, which I would prefer because of readability:
public List<Employee> GetApplicant(int ApplicationID)
{
var context = new FPSDB_newEntities();
var data = context.Applications.Where(p=>p.ApplicationID == ApplicationID).Select(p=>p.Employee).ToList();
return data;
}

StoreRequestParameters,get the values issue

on the web service side I am applying
StoreRequestParameters parameters = new StoreRequestParameters(this.Context);
string condition= parameters.GridFilters.ToString();
//I ma sending this to the methot "List<Ks> Get(....)"
to get the gridfilter parameters.
inside the other methot ,trying to get the selected gridfilters values like this.
public List<Ks> Get(int start, int limit, string sort, string terssiralama, string condition, out int totalrow)
{
FilterConditions fc = new FilterConditions(condition);
foreach (FilterCondition cnd in fc.Conditions)
{
Comparison comparison = cnd.Comparison;
string fi = cnd.Field;
FilterType type = cnd.Type;
switch (cnd.Type)
{
case FilterType.Date:
switch (comparison)
{
case Comparison.Eq:
field1 = cnd.Field;
cmp1 = "=";
value1 = cnd.Value<string>();
...........
..........
}
but I failed getting the values like this
FilterConditions fc = new FilterConditions(condition);
I couldnt pass the string values .
should I serializes or deserilized first ?
StoreRequestParameters parameters = new StoreRequestParameters(this.Context);
instead of using this, string condition= parameters.GridFilters.ToString();
I use this
string obj = this.Context.Request["filter"];
and pass it to the
FilterConditions fc = new FilterConditions(obj);
It can be reach all filter condition in fc filtercondition variable.

Asp.net, C#, Linq and Array usage,

var result = (from p in productInQuery
join o in orderInfoQuery on p.refNo equals o.refNo
join x in productQuery on p.productNo equals x.no
join t in productOutQuery on p.no equals t.productInNo into productIn
from t in productIn.DefaultIfEmpty()
//let dateOut = (from m in orderInfoQuery where m.refNo == t.refNo select m.delivered).FirstOrDefault()
orderby o.processDate descending
select new
{
modelNo = x.modelNo,
mfgNo = p.mfgNo,
serialNo = p.serialNo,
poNo = p.poNo,
lbs = p.lbs,
width = p.width,
height = p.height,
depth = p.depth,
qty = p.qty,
dateIn = o.processDate,
dateOut = (DateTime?)(from m in orderInfoQuery where m.refNo == t.refNo select m.processDate).FirstOrDefault()
}).ToArray();
I want to add this result into iTextSharp table cell.
but I don't know how to do,
I tried,
int resultSize = result.Length;
/*
for (int j = 0; j < resultSize; j++)
{
table.AddCell(result[j]);
}
*/
foreach (string[] test in result) //Error : Unable to cast object of type
{
int testSize = test.Length;
for (int j = 0; j < testSize; j++)
{
table.AddCell(test[j]);
}
}
but I lost way :(
anybody knows, please advice me~
[EDIT]
int resultSize = result.Length; //192
test does have a fields...
[EDIT 2]
Actually the result be returned from Model.
PJ.WebUI.Models Reports Class
public class Reports
{
public Array GetTransaction(){
OrdersRepository ordersRepository = new OrdersRepository();
var productInQuery = ordersRepository.ProductIn;
var productOutQuery = ordersRepository.ProductOut;
var productQuery = ordersRepository.Product;
var orderInfoQuery = ordersRepository.OrderInfo;
var result = (from p in productInQuery
join o in orderInfoQuery on p.refNo equals o.refNo
join x in productQuery on p.productNo equals x.no
join t in productOutQuery on p.no equals t.productInNo into productIn
from t in productIn.DefaultIfEmpty()
//let dateOut = (from m in orderInfoQuery where m.refNo == t.refNo select m.delivered).FirstOrDefault()
orderby o.processDate descending
select new
{
modelNo = x.modelNo,
mfgNo = p.mfgNo,
serialNo = p.serialNo,
poNo = p.poNo,
lbs = p.lbs,
width = p.width,
height = p.height,
depth = p.depth,
qty = p.qty,
dateIn = o.processDate,
dateOut = (DateTime?)(from m in orderInfoQuery where m.refNo == t.refNo select m.processDate).FirstOrDefault()
}).ToArray();
return result;
}
}
And in controller call the method to get the result.
Reports reposrts = new Reports();
var result = reposrts.GetTransaction();
..
foreach (var test in result)
{
table.AddCell(test.modelNo);
}
Then
Error 1 'object' does not contain a definition for 'modelNo' and no extension method 'modelNo' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
So,
I move the model method into controller method (put all together in same method) and run. then it works!.
but the result be used in the other controller too. so I want to keep the result in Model class to reuse.
I want to know why it does not work if the result query is not in same method.
could you help me a little more please?
Thank you very much!
'result' will be an array of the anonymous type you selected to, not an array of string arrays, which is why you are getting an error in the foreach loop.
Your loop should probably look more like the following:
foreach (var test in result)
{
table.AddCell(test.modelNo);
table.AddCell(test.mfgNo);
table.AddCell(test.serialNo);
// etc
}
#Edit 2:
Because the result of GetTransaction() is 'Array', the calling method has no idea what the type is, it just sees it as an array of objects, and, because it is an anonymous type, you can't (reasonably) cast it back to the expected type.
I think your best bet in this case would be to make a new class which has the properties you want to return, e.g.:
public class Transaction
{
public string ModelNo { get; set; }
public string MfgNo { get; set; }
public string SerialNo { get; set; }
// etc. - but with the correct types for the properties
}
Then change the linq query to select into this type, instead of the anonymous type, e.g.:
...
orderby o.processDate descending
select new Transaction
{
ModelNo = x.modelNo,
MfgNo = p.mfgNo,
SerialNo = p.serialNo,
// etc.
...
And change the return type of GetTransaction() from Array to Transaction[].
It's not clear what you are trying to do but I believe you are casting each element of your result as a string incorrectly.
Try this:
foreach (var test in result)
You will probably need to tweak your inner code since test isn't an array, but that should get you past your current error.

how to add additional name-value pair in an existing flex object

folks,
I have a question regarding adding additional name-value pairs to my existing object in Flex;
I have an object1 of Object Type
and I declare a new object2 = object1 plus some extra name-value pairs,
is there a way to attach new name-value pairs to an existing object?
Many thanks,
If I understand your question correctly, object2 is a reference pointer to object1; therefore, changes to object2 affect object1:
package
{
import flash.display.Sprite;
public class X extends Sprite
{
public function X()
{
var object1:Object = {a: "1", b: "2"};
var object2:Object = object1;
object2.c = 3;
trace("Object 2:");
for (var name:String in object2)
{
trace("Name: " + name + " = " + object2[name]);
}
trace("Object 1:");
for (var name:String in object1)
{
trace("Name: " + name + " = " + object1[name]);
}
}
}
}
...which outputs:
Object 2:
Name: a = 1
Name: c = 3
Name: b = 2
Object 1:
Name: a = 1
Name: c = 3
Name: b = 2
If you are asking whether an object or dynamic class may be cloned, you could use a function like this:
public function cloneObject(object:Object):Object
{
var newObject:Object = {};
for (var name:String in object)
{
newObject[name] = object[name];
}
return newObject;
}

Comparing two lists using LINQ

If I have 2 lists of strings:
List<string> firstList = new List<string>("010", "111", "123");
List<string> secondList = new List<string>("010", "111", "999");
How can I compare each individual character in each item from the lists? Ex: Should compare "0" with "0", "1" with "1", "0" with "0" and so on. It appears that I can use SelectMany but I am stuck on how to do it
EDIT:
These lists should return true when compared with each other (as asterisk means any character and I am validating to ensure that each item is exactly 3 chars in length)
List<string> firstList = new List<string>("010", "111", "123");
List<string> secondList = new List<string>("010", "1*1", "***");
Updated with wildcards
class WildcardStringComparer : IEqualityComparer<string>
{
public bool Equals(string s1, string s2)
{
if (s1.Length != s2.Length) return false;
for (int i = 0; i < s1.Length; i++)
{
if (s1[i] != s2[i] && s1[i] != '*' && s2[i] != '*')
return false;
}
return true;
}
public int GetHashCode(string obj)
{
throw new NotImplementedException();
}
}
Results:
List<string> firstList = new List<string>{"010", "111", "999"};
List<string> secondList = new List<string>{"010", "111", "999"};
bool res = firstList.SequenceEqual(secondList, new WildcardStringComparer()); // True
and
List<string> firstList = new List<string>{"010", "111", "999"};
List<string> secondList = new List<string>{"010", "111", "*99"};
bool res = firstList.SequenceEqual(secondList, new WildcardStringComparer()); // True
and
List<string> firstList = new List<string>{"010", "111", "999"};
List<string> secondList = new List<string>{"010", "111", "199"};
bool res = firstList.SequenceEqual(secondList, new WildcardStringComparer()); // False
If you just want to compare for a matching character sequence between your lists:
bool sameCharacters = Enumerable.SequenceEqual(firstList.SelectMany(x => x),
secondList.SelectMany(x => x));
This would result in true, i.e. for the following two lists - their character sequences match ("010111123" for both), their individual string entries do not:
List<string> firstList = new List<string> {"010", "111", "123" };
List<string> secondList = new List<string> {"010", "11", "1123" };
Edit in response to comments:
For a wildcard match you could use Zip() and compare each character, return true if they match based on wildcard conditions, then just check that each element in the zipped sequence is true.
var isWildCardMatch = firstList.SelectMany(x => x).Zip(secondList.SelectMany( x => x),
(a,b) =>
{
if(a==b || a =='' || b == '')
return true;
return false;
}).All( x=> x);
Above approach crossed string entry boundaries, which would cause false matches - here a better approach:
bool isWildCardMatch = firstList.Zip(secondList, (x, y) =>
{
var matchWord = y.Select((c, i) => c == '*' ? x[i] : c);
return matchWord.SequenceEqual(x);
}).All(x => x);
Assuming you want to compare the first character of the first string in the first list to the first character of the first string of the second list, the second character of the first string in the first list to the second character of the first string in the second list, etc. I can think of two implementations.
The one I would start with:
var firstCharList = new List<char>();
var secondCharList = new List<char>();
firstList.foreach(s =>
{
foreach(char c in s)
{
firstCharList.Add(c);
}
});
secondList.foreach(s =>
{
foreach(char c in s)
{
secondCharList.Add(c);
}
});
for(int i = 0; i < firstCharList.Length; i++)
{
if(firstCharList[i] == secondCharList[i]) yield return i;
}
That would generate a list (or array, or whatever) of ints that correspond to indexes of which both strings had the same character.
The second would be something like:
firstList.foreach(s =>
{
var index = firstList.IndexOf(s);
var sPrime = secondList[index];
for(int i = 0; i < s.Length; i++)
{
if(s[i] == sPrime[i]) yield return s[i];
}
}
That one just returns any characters that are equal at the same indexes.

Resources