Translating java DFS algorithm code to Dart - flutter

I've been doing some research to find a suitable algorithm for suggesting friends. I came across DFS, but I've never implemented it in Dart before. Could someone please help me t translate it into Dart? Below is the java code:
public class SuggestFriendsDFS<T> {
private HashMap<T, ArrayList<T>> adj = new HashMap<>(); //graph
private List<Set<T>> groups = new ArrayList<>();
public void addFriendship(T src, T dest) {
adj.putIfAbsent(src, new ArrayList<T>());
adj.get(src).add(dest);
adj.putIfAbsent(dest, new ArrayList<T>());
adj.get(dest).add(src);
}
//V is total number of people, E is number of connections
private void findGroups() {
Map<T, Boolean> visited = new HashMap<>();
for (T t: adj.keySet())
visited.put(t, false);
for (T t:adj.keySet()) {
if (!visited.get(t)) {
Set<T> group = new HashSet<>();
dfs(t, visited, group);
groups.add(group);
}
}
}
//DFS + memoization
private void dfs(T v, Map<T, Boolean> visited, Set<T> group ) {
visited.put(v,true);
group.add(v);
for (T x : adj.get(v)) {
if (!visited.get(x))
dfs(x, visited, group);
}
}
public Set<T> getSuggestedFriends (T a) {
if (groups.isEmpty())
findGroups();
Set<T> res = new HashSet<>();
for (Set<T> t : groups) {
if (t.contains(a)) {
res = t;
break;
}
}
if (res.size() > 0)
res.remove(a);
return res;
}
}
I'm aware it's too much to ask, but any help will be much appreciated as I tried to translate it and ended up getting loads of errors. Thanks in advance!(: For reference, this is where I found the explanation for the java code.

I tried https://sma.github.io/stuff/java2dartweb/java2dartweb.html that does automatic Java to Dart conversion but it doesn't work well as soon as the code is a bit complex.
See the full conversion below, you can try it in Dartpad
import 'dart:collection';
class SuggestFriendsDFS<T> {
final HashMap<T, List<T>> _adj = HashMap(); //graph
final List<Set<T>> groups = [];
//Time O(1), Space O(1)
void addFriendship(T src, T dest) {
_adj.putIfAbsent(src, () => <T>[]);
_adj[src]!.add(dest);
_adj.putIfAbsent(dest, () => <T>[]);
_adj[dest]!.add(src);
}
//DFS wrapper, Time O(V+E), Space O(V)
//V is total number of people, E is number of connections
void findGroups() {
Map<T, bool> visited = HashMap();
for (T t in _adj.keys) {
visited[t] = false;
}
for (T t in _adj.keys) {
if (visited[t] == false) {
Set<T> group = HashSet();
_dfs(t, visited, group);
groups.add(group);
}
}
}
//DFS + memoization, Time O(V+E), Space O(V)
void _dfs(T v, Map<T, bool> visited, Set<T> group) {
visited[v] = true;
group.add(v);
for (T x in _adj[v] ?? []) {
if ((visited[x] ?? true) == false) _dfs(x, visited, group);
}
}
//Time O(V+E), Space O(V)
Set<T> getSuggestedFriends(T a) {
if (groups.isEmpty) findGroups();
var result = groups.firstWhere((element) => element.contains(a),
orElse: () => <T>{});
if (result.isNotEmpty) result.remove(a);
return result;
}
}
void main() {
SuggestFriendsDFS<String> g = SuggestFriendsDFS();
g.addFriendship("Ashley", "Christopher");
g.addFriendship("Ashley", "Emily");
g.addFriendship("Ashley", "Joshua");
g.addFriendship("Bart", "Lisa");
g.addFriendship("Bart", "Matthew");
g.addFriendship("Christopher", "Andrew");
g.addFriendship("Emily", "Joshua");
g.addFriendship("Jacob", "Christopher");
g.addFriendship("Jessica", "Ashley");
g.addFriendship("JorEl", "Zod");
g.addFriendship("KalEl", "JorEl");
g.addFriendship("Kyle", "Lex");
g.addFriendship("Kyle", "Zod");
g.addFriendship("Lisa", "Marge");
g.addFriendship("Matthew", "Lisa");
g.addFriendship("Michael", "Christopher");
g.addFriendship("Michael", "Joshua");
g.addFriendship("Michael", "Jessica");
g.addFriendship("Samantha", "Matthew");
g.addFriendship("Samantha", "Tyler");
g.addFriendship("Sarah", "Andrew");
g.addFriendship("Sarah", "Christopher");
g.addFriendship("Sarah", "Emily");
g.addFriendship("Tyler", "Kyle");
g.addFriendship("Stuart", "Jacob");
g.findGroups();
print(g.groups);
String name = "Andrew";
print("Suggestion friends of " +
name +
": " +
g.getSuggestedFriends(name).toString());
}

Related

Java 8 group by sum condition

I have an object Officer
public class Officer {
private String name;
private int totalDaysInOffice;
public Officer(String name, int totalDaysInOffice) {
this.name = name;
this.totalDaysInOffice = totalDaysInOffice;
}
#Override
public String toString() {
return "Officer{" +
"name='" + name + '\'' +
", totalDaysInOffice=" + totalDaysInOffice +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getTotalDaysInOffice() {
return totalDaysInOffice;
}
public void setTotalDaysInOffice(int totalDaysInOffice) {
this.totalDaysInOffice = totalDaysInOffice;
}
}
Here each officer have spent days in office(just made up variable).
What I want to do is the divide the officers once I have the sum of days 10000 in separate list
Based on example below , I want to have list with
one list with John , Matthew , and Robert since they sum to more 10K
One list with Patrick as he has 10K
Dave would be in separate list.
I have tried group by but not sure how can I add this condition.
public class OffierExample {
public static void main(String[] args) {
List<Officer> officerList = new ArrayList<>();
officerList.add(new Officer("John",5000));
officerList.add(new Officer("Matthew",3000));
officerList.add(new Officer("Robert",2000));
officerList.add(new Officer("Dave",2000));
officerList.add(new Officer("Patrick",10000));
Map<Officer, Integer> collect = officerList.stream().collect(Collectors.groupingBy(o -> o, Collectors.summingInt(Officer::getTotalDaysInOffice)));
System.out.println(collect);
}
}
Is there anyways it can be done in Java 8
**
*****UPDATE*****
**
I have achieved using traditional loop but I want to use Java 8 group by if possible
public class OffierExample {
public static void main(String[] args) {
List<Officer> officerList = new ArrayList<>();
officerList.add(new Officer("John", 5000));
officerList.add(new Officer("Matthew", 3000));
officerList.add(new Officer("Robert", 2000));
officerList.add(new Officer("Dave", 2000));
officerList.add(new Officer("Patrick", 10000));
officerList.add(new Officer("YYYY", 600));
officerList.add(new Officer("XXXX", 600));
//keep totalDaysInOfficeSum
int totalDaysInOfficeSum = 0;
//the final list
List<List<Officer>> off = Lists.newArrayList();
//the working list
List<Officer> tempOffList = Lists.newArrayList();
for (Officer officer : officerList) {
//get sum
totalDaysInOfficeSum = totalDaysInOfficeSum + officer.getTotalDaysInOffice();
//if sum is more than 10K or equal
if (totalDaysInOfficeSum >= 10000) {
//add it in temp list
tempOffList.add(officer);
//add in master list
off.add(tempOffList);
//reset temp list
tempOffList = new ArrayList<>();
//reset sum
totalDaysInOfficeSum = 0;
continue;
}
//add in temp list
tempOffList.add(officer);
}
//any left over
if (!tempOffList.isEmpty()) {
off.add(tempOffList);
}
//printint out
System.out.println("Officers list =" + off.size());
off.forEach(o -> {
System.out.println("List size:" + o.size());
o.forEach(oo -> {
System.out.println(oo.getName() + "::" + oo.getTotalDaysInOffice());
});
System.out.println("====================");
});
}
}
Output
Officers list =3
List size:3
John::5000
Matthew::3000
Robert::2000
====================
List size:2
Dave::2000
Patrick::10000
====================
List size:2
YYYY::600
XXXX::600
====================
Something like this:
List<List<Officer>> result = officerList.stream().collect(Collector.of(
() -> new ArrayList<List<Officer>>(),
(list, entry) -> {
if (list.size() == 0) {
List<Officer> inner = new ArrayList<>();
inner.add(entry);
list.add(inner);
} else {
List<Officer> last = list.get(list.size() - 1);
int sum = last.stream().mapToInt(Officer::getTotalDaysInOffice).sum();
if (sum < 10_000) {
last.add(entry);
} else {
List<Officer> inner = new ArrayList<>();
inner.add(entry);
list.add(inner);
}
}
},
(left, right) -> {
throw new IllegalArgumentException("Not for parallel");
}));
Here is the solution with my library:
MutableInt sum = MutableInt.of(0);
List<List<Officer>> off = Stream.of(officerList)
.splitToList(officer -> sum.getAndSet(sum.value() < 10000 ? sum.value() + officer.getTotalDaysInOffice() : 0) < 10000)
.toList();
Or:
List<List<Officer>> off = Seq.of(officerList)
.split(officer -> sum.getAndSet(sum.value() < 10000 ? sum.value() + officer.getTotalDaysInOffice() : 0) < 10000);
Java 8 way
List<Officer> officerList = new ArrayList<>();
officerList.add(new Officer("John", 5000));
officerList.add(new Officer("Matthew", 3000));
officerList.add(new Officer("Robert", 2000));
officerList.add(new Officer("Dave", 2000));
officerList.add(new Officer("Patrick", 10000));
List<List<Officer>> separatedOfficerLists = officerList.stream()
.sorted(Comparator.comparing(Officer::getTotalDaysInOffice).reversed())
.collect(Collectors.groupingByConcurrent(o -> {
int totalDays = o.getTotalDaysInOffice();
int divisor = (totalDays / 10000) + 1;
return (divisor * 10000) - totalDays;
})).entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(Map.Entry::getValue)
.collect(Collectors.toList());
System.out.println(separatedOfficerLists);

How to get the average of a generic array list in java?

i'm having trouble getting the average of a generic array list of type T.
You should use <T extends Number> generic signature to specify the type of the Number types, plus, you should use instanceof keyword. A simple dummy demo here;
Test Code
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<Integer>();
List<Double> doubleList = new ArrayList<Double>();
List<Float> floatList = new ArrayList<Float>();
for(int i = 0; i < 10; i++)
{
integerList.add(new Integer(i+1));
doubleList.add(new Double(i+1));
floatList.add(new Float(i+1));
}
Utility<Integer> utilityInteger = new Utility<Integer>(integerList);
Utility<Double> utilityDouble = new Utility<Double>(doubleList);
Utility<Float> utilityFloat = new Utility<Float>(floatList);
System.out.println("Integer average: " + utilityInteger.getAverage());
System.out.println("Double average : " + utilityDouble.getAverage());
System.out.println("Float average : " + utilityFloat.getAverage());
}
public static class Utility<T extends Number>
{
// Fields
private List<T> list;
private Object average;
// Constructor
#SuppressWarnings("unchecked")
public Utility(List<T> list)
{
this.list = list;
T sample = list.get(0);
if(sample instanceof Double)
{
doAverageDouble((List<Double>) list);
}
else if (sample instanceof Integer)
{
doAverageInteger((List<Integer>) list);
}
else if (sample instanceof Float)
{
doAverageFloat((List<Float>) list);
}
else
{
throw new IllegalStateException("Constructor must be initialiez with either of Double, Integer or Float list");
}
}
// Methods
private void doAverageDouble(List<Double> list) {
Double sum = new Double(0);
for(Double d : list)
{
sum += d;
}
average = sum/new Double(list.size());
}
private void doAverageInteger(List<Integer> list) {
Integer sum = new Integer(0);
for(Integer d : list)
{
sum += d;
}
average = sum/new Integer(list.size());
}
private void doAverageFloat(List<Float> list) {
Float sum = new Float(0);
for(Float d : list)
{
sum += d;
}
average = sum/new Float(list.size());
}
Object getAverage()
{
return average;
}
}
}
Console Output
Integer average: 5
Double average : 5.5
Float average : 5.5

Implementing resource queue in rx

I have a hot observable Observable<Resource> resources that represents consumable resources and I want to queue up consumers Action1<Resource> for these resources. A Resource can be used by at most 1 consumer. It should not be used at all once a new value is pushed from resources. If my consumers were also wrapped in a hot observable then the marble-diagram of what I'm after would be
--A--B--C--D--E--
----1----2--34---
----A----C--D-E--
----1----2--3-4--
I've managed a naive implementation using a PublishSubject and zip but this only works if each resource is consumed before a new resource is published (i.e. instead of the required sequence [A1, C2, D3, E4] this implementation will actually produce [A1, B2, C3, D4]).
This is my first attempt at using rx and I've had a play around with both delay and join but can't quite seem to get what I'm after. I've also read that ideally Subjects should be avoided, but I can't see how else I would implement this.
public class ResourceQueue<Resource> {
private final PublishSubject<Action1<Resource>> consumers = PublishSubject.create();
public ResourceQueue(Observable<Resource> resources) {
resources.zipWith(this.consumers, new Func2<Resource, Action1<Resource>, Object>() {
#Override
public Object call(Resource resource, Action1<Resource> consumer) {
consumer.execute(resource);
return null;
}
}).publish().connect();
}
public void queue(final Action1<Resource> consumer) {
consumers.onNext(consumer);
}
}
Is there a way to achieve what I'm after? Is there a more 'rx-y' approach to the solution?
EDIT: changed withLatesFrom suggestion with combineLatest.
The only solution I can think of is to use combineLatest to get all the possible combinations, and manually exclude the ones that you do not need:
final ExecutorService executorService = Executors.newCachedThreadPool();
final Observable<String> resources = Observable.create(s -> {
Runnable r = new Runnable() {
#Override
public void run() {
final List<Integer> sleepTimes = Arrays.asList(200, 200, 200, 200, 200);
for (int i = 0; i < sleepTimes.size(); i++) {
try {
Thread.sleep(sleepTimes.get(i));
} catch (Exception e) {
e.printStackTrace();
}
String valueOf = String.valueOf((char) (i + 97));
System.out.println("new resource " + valueOf);
s.onNext(valueOf);
}
s.onCompleted();
}
};
executorService.submit(r);
});
final Observable<Integer> consumers = Observable.create(s -> {
Runnable r = new Runnable() {
#Override
public void run() {
final List<Integer> sleepTimes = Arrays.asList(300, 400, 200, 0);
for (int i = 0; i < sleepTimes.size(); i++) {
try {
Thread.sleep(sleepTimes.get(i));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("new consumer " + (i + 1));
s.onNext(i + 1);
}
s.onCompleted();
};
};
executorService.submit(r);
});
final LatestValues latestValues = new LatestValues();
final Observable<String> combineLatest = Observable.combineLatest(consumers, resources, (c, r) -> {
if (latestValues.alreadyProcessedAnyOf(c, r)) {
return "";
}
System.out.println("consumer " + c + " will consume resource " + r);
latestValues.updateWithValues(c, r);
return c + "_" + r;
});
combineLatest.subscribe();
executorService.shutdown();
executorService.awaitTermination(10, TimeUnit.SECONDS);
The class holding the latest consumers and resources.
static class LatestValues {
Integer latestConsumer = Integer.MAX_VALUE;
String latestResource = "";
public boolean alreadyProcessedAnyOf(Integer c, String r) {
return latestConsumer.equals(c) || latestResource.equals(r);
}
public void updateWithValues(Integer c, String r) {
latestConsumer = c;
latestResource = r;
}
}

Reactive Extensions Group By, Unique BufferWindow till time span with cancellation

I have a Hot stream of events coming of following type:
Event
{
string name;
int state ; // its 1 or 2 ie active or unactive
}
there is a function which provides parent name of given name - string GetParent(string name)
I need to buffer event per parent for 2 minutes, if during this 2 minute , i recv any event for child with state =2 for a given parent , this buffer should cancel and should output 0 otherwise i get the count of the events recvd .
I know I have to use GroupBy to partition, and then buffer and then count but i am unable to think of a way by which i create Buffer which is unique per parent, i though of using Distinct but this doesnt solve the problem, for i only dont want to create buffer till the parent is active (as once the parent's buffer gets cancelled or 2 minutes is over, the parent buffer can be created again)
So I understand I need to create a custom buffer which checks the condition for creating buffer, but how do i do this via reactive extensions.
Any help will be greatly appreciated.
regards
Thanks Brandon for your help. This is the main program I am using for testing. Its not working.As I am new to reactive extension problem can be in the way i am testing
namespace TestReactive
{
class Program
{
static int abc = 1;
static void Main(string[] args)
{
Subject<AEvent> memberAdded = new Subject<AEvent>();
//ISubject<AEvent, AEvent> syncedSubject = new ISubject<AEvent, AEvent>();
var timer = new Timer { Interval = 5 };
timer.Enabled = true;
timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, memberAdded);
var bc = memberAdded.Subscribe();
var cdc = memberAdded.GroupBy(e => e.parent)
.SelectMany(parentGroup =>
{
var children = parentGroup.Publish().RefCount();
var inactiveChild = children.SkipWhile(c => c.state != 2).Take(1).Select(c => 0);
var timer1 = Observable.Timer(TimeSpan.FromSeconds(1));
var activeCount = children.TakeUntil(timer1).Count();
return Observable.Amb(activeCount, inactiveChild)
.Select(count => new { ParentName = parentGroup.Key, Count = count });
});
Observable.ForEachAsync(cdc, x => WriteMe("Dum Dum " + x.ParentName+x.Count));
// group.Dump("Dum");
Console.ReadKey();
}
static void WriteMe(string sb)
{
Console.WriteLine(sb);
}
static void MyElapsedMethod(object sender, ElapsedEventArgs e, Subject<AEvent> s)
{
AEvent ab = HelperMethods.GetAlarm();
Console.WriteLine(abc + " p =" + ab.parent + ", c = " + ab.name + " ,s = " + ab.state);
s.OnNext(ab);
}
}
}
public static AEvent GetAlarm()
{
if (gp> 4)
gp = 1;
if (p > 4)
p = 1;
if (c > 4)
c = 1;
AEvent a = new AEvent();
a.parent = "P" + gp + p;
a.name = "C" + gp + p + c;
if (containedKeys.ContainsKey(a.name))
{
a.state = containedKeys[a.name];
if (a.state == 1)
containedKeys[a.name] = 2;
else
containedKeys[a.name] = 1;
}
else
{
containedKeys.TryAdd(a.name, 1);
}
gp++; p++; c++;
return a;
}
So this method , generates a event for Parent at each tick. It generates event for parent P11,P22,P33,P44 with State =1 and then followed by events for Parent P11,P22,P33,P44 with State =2
I am using Observable.ForEach to print the result, I see its being called 4 times and after that its nothing, its like cancellation of group is not happening
Assuming that a two minute buffer for each group should open as soon as the first event for that group is seen, and close after two minutes or a zero state is seen, then I think the following works:
public static IObservable<EventCount> EventCountByParent(
this IObservable<Event> source, IScheduler scheduler)
{
return Observable.Create<EventCount>(observer => source.GroupByUntil(
evt => GetParent(evt.Name),
evt => evt,
group =>
#group.Where(evt => evt.State == 2)
.Merge(Observable.Timer(
TimeSpan.FromMinutes(2), scheduler).Select(_ => Event.Null)))
.SelectMany(
go =>
go.Aggregate(0, (acc, evt) => (evt.State == 2 ? 0 : acc + 1))
.Select(count => new EventCount(go.Key, count))).Subscribe(observer));
}
With EventCount (implementing equality overrides for testing) as:
public class EventCount
{
private readonly string _name;
private readonly int _count;
public EventCount(string name, int count)
{
_name = name;
_count = count;
}
public string Name { get { return _name; } }
public int Count { get { return _count; } }
public override string ToString()
{
return string.Format("Name: {0}, Count: {1}", _name, _count);
}
protected bool Equals(EventCount other)
{
return string.Equals(_name, other._name) && _count == other._count;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((EventCount) obj);
}
public override int GetHashCode()
{
unchecked
{
return ((_name != null ? _name.GetHashCode() : 0)*397) ^ _count;
}
}
}
And Event as:
public class Event
{
public static Event Null = new Event(string.Empty, 0);
private readonly string _name;
private readonly int _state;
public Event(string name, int state)
{
_name = name;
_state = state;
}
public string Name { get { return _name; } }
public int State { get { return _state; } }
}
I did a quick (i.e. not exhaustive) test with Rx-Testing:
public class EventCountByParentTests : ReactiveTest
{
private readonly TestScheduler _testScheduler;
public EventCountByParentTests()
{
_testScheduler = new TestScheduler();
}
[Fact]
public void IsCorrect()
{
var source = _testScheduler.CreateHotObservable(
OnNext(TimeSpan.FromSeconds(10).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(20).Ticks, new Event("B", 1)),
OnNext(TimeSpan.FromSeconds(30).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(40).Ticks, new Event("B", 1)),
OnNext(TimeSpan.FromSeconds(50).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(60).Ticks, new Event("B", 2)),
OnNext(TimeSpan.FromSeconds(70).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(140).Ticks, new Event("A", 1)),
OnNext(TimeSpan.FromSeconds(150).Ticks, new Event("A", 1)));
var results = _testScheduler.CreateObserver<EventCount>();
var sut = source.EventCountByParent(_testScheduler).Subscribe(results);
_testScheduler.Start();
results.Messages.AssertEqual(
OnNext(TimeSpan.FromSeconds(60).Ticks, new EventCount("B", 0)),
OnNext(TimeSpan.FromSeconds(130).Ticks, new EventCount("A", 4)),
OnNext(TimeSpan.FromSeconds(260).Ticks, new EventCount("A", 2)));
}
}
something like....
source.GroupBy(e => GetParent(e.name))
.SelectMany(parentGroup =>
{
var children = parentGroup.Publish().RefCount();
var inactiveChild = children.SkipWhile(c => c.state != 2).Take(1).Select(c => 0);
var timer = Observable.Timer(TimeSpan.FromMinutes(2));
var activeCount = children.TakeUntil(timer).Count();
return Observable.Amb(activeCount, inactiveChild)
.Select(count => new { ParentName = parentGroup.Key, Count = count };
});
This will give you a sequence of { ParentName, Count } objects.

From AutoMapper to Emit Mapper

I've recently discovered AutoMapper for bridging ViewModels and my actual DB objects. I use it in the way decribed here: http://automapper.codeplex.com/wikipage?title=Projection&referringTitle=Home
I've discovered Emit Mapper to :), but I can't find anytning similar to (where I can specify custom projecting rules):
.ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.EventDate.Date))
Thanks in advance!
For the Record this is the best solution that I came across on how to do it:
http://emitmapper.codeplex.com/discussions/259655
Check the solution on the last post. It works really well.
Update: The code for future reference:
public class ExtDefaultMapConfig<TSrc, TDst> : DefaultMapConfig
{
private readonly Dictionary<string, Func<TSrc, object>> _properties = new Dictionary<string, Func<TSrc, object>>();
public ExtDefaultMapConfig<TSrc, TDst> ForMember(string property, Func<TSrc, object> func)
{
if (!_properties.ContainsKey(property))
_properties.Add(property, func);
return this;
}
public ExtDefaultMapConfig<TSrc, TDst> ForMember(Expression<Func<TDst, object>> dstMember, Func<TSrc, object> func)
{
var prop = ReflectionHelper.FindProperty(dstMember);
return ForMember(prop.Name, func);
}
public ExtDefaultMapConfig<TSrc, TDst> Ignore(Expression<Func<TDst, object>> dstMember)
{
var prop = ReflectionHelper.FindProperty(dstMember);
IgnoreMembers<TSrc, TDst>(new[] { prop.Name });
return this;
}
public override IMappingOperation[] GetMappingOperations(Type from, Type to)
{
var list = new List<IMappingOperation>();
list.AddRange(base.GetMappingOperations(from, to));
list.AddRange(
FilterOperations(
from,
to,
ReflectionUtils.GetPublicFieldsAndProperties(to)
.Where(f => _properties.ContainsKey(f.Name))
.Select(
m =>
(IMappingOperation)new DestWriteOperation
{
Destination = new MemberDescriptor(m),
Getter =
(ValueGetter<object>)
(
(value, state) =>
{
Debug.WriteLine(string.Format("Mapper: getting value of field or property {0}", m.Name));
return ValueToWrite<object>.ReturnValue(_properties[m.Name]((TSrc) value));
}
)
}
)
)
);
return list.ToArray();
}
}
class ReflectionHelper
{
public static MemberInfo FindProperty(LambdaExpression lambdaExpression)
{
Expression expression = lambdaExpression;
bool flag = false;
while (!flag)
{
switch (expression.NodeType)
{
case ExpressionType.Convert:
expression = ((UnaryExpression)expression).Operand;
break;
case ExpressionType.Lambda:
expression = ((LambdaExpression)expression).Body;
break;
case ExpressionType.MemberAccess:
MemberExpression memberExpression = (MemberExpression)expression;
if (memberExpression.Expression.NodeType != ExpressionType.Parameter && memberExpression.Expression.NodeType != ExpressionType.Convert)
throw new ArgumentException(string.Format("Expression '{0}' must resolve to top-level member.", lambdaExpression), "lambdaExpression");
return memberExpression.Member;
default:
flag = true;
break;
}
}
return null;
}
public static object GetValue(string property, object obj)
{
PropertyInfo pi = obj.GetType().GetProperty(property);
return pi.GetValue(obj, null);
}
}