HashMap<String, Set<Myclass>> mapNew = new HashMap<String, Set<Myclass>>();
for (Map.Entry<String, Set< Myclass >> entry : mapOrig.entrySet()) {
mapNew.put(entry.getKey(), entry.getValue().clone());
}
.clone() does not work here
I want to change an item in the new but leave the original unaffected.
I came up with this but it seems awkward. Is there a better way?
for (Map.Entry<String, Set< Myclass >> entry : mapOrig.entrySet()) {
Set<Myclass> objs = entry.getValue();
Set<Myclass> objsCloned = new HashSet<Myclass>();
for(Myclass obj : objs)
{
objsCloned.add(obj.clone());
}
mapNew.put(entry.getKey(), objsCloned);
}
Related
Have started to Make the conversion faster from dataTable to List as I have 20K record in datatable and converting it in normal way takes 5 to 7 Minutes. SO I thought to Make it faster by using Parallel.ForEach or Task but still no benefit - Any suggestion please. Mu code is as below :
public static List<T> FillFromStoredProc<T>(string storedproc, SqlParameter[] prms) where T : IReadOnlyDatabaseObject, new()
{
DataTable dt = DatabaseHelper.runStoredProc(Configuration.Instance.ConnectionString, storedproc, prms);
ConcurrentBag<T> bag = new ConcurrentBag<T>();
IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
Parallel.ForEach(dt.AsEnumerable(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, Drow => {
bag.Add(GetFromDataRow<T>(Drow, properties));
});
return bag.ToList();
}
public static T GetFromDataRow<T>(DataRow dr, IList<PropertyInfo> properties) where T : IReadOnlyDatabaseObject, new()
{
T ret = new T();
ret.LoadFromDataRowAsync(dr, properties);
return ret;
}
public virtual void LoadFromDataRowAsync(DataRow dr, IList<PropertyInfo> properties)
{
Parallel.ForEach(properties, new ParallelOptions { MaxDegreeOfParallelism = 10 }, prop =>
{
try
{
if (dr.Table.Columns.Contains(prop.Name))
{
if (prop.PropertyType.BaseType.Name == "Enum")
{
prop.SetValue(this, Enum.Parse(prop.PropertyType, dr[prop.Name].ToString()));
}
else
{
var val = DatabaseHelper.ConvertFromDBVal(prop.GetType(), dr[prop.Name]);
if (prop.PropertyType == typeof(DateTime))
{
// Convert back from DB value
if ((DateTime)(val) == SqlDateTime.MinValue)
{
val = DateTime.MinValue;
}
}
prop.SetValue(this, val);
}
}
}
catch
{
}
});
}
Please help me to make this faster. Thanks
Nesting parallelism is useless and must be avoided, because usually it only makes the overall performance worse.
Your bottleneck is the reflection - it is slow. You should come up with an alternative. For example, you can create a base class for your generic types, and use a virtual method that maps the name of a property to an actual property. It sounds like quite some grinding and dirty work, but it will be more efficient.
I am trying to read an excel sheet and save it in Java Data Structure List> list
Basically I am having a table in the excel sheet
|Name|FirstName|emp_ID|Age|
|aaaa|bbbbbbbbb|111111|40 |
|cccc|fffffffff|222222|25 |
where the keys will be
|Name|FirstName|emp_ID|Age|
my list of map should look as bellow
{Name=aaaa, FirstName=bbbbbbbbb, emp_ID=111111, Age=40}
{Name=cccc, FirstName=fffffffff, emp_ID=222222, Age=25}
but my list is storing the second map two times
{Name=cccc, FirstName=fffffffff, emp_ID=222222, Age=25}
{Name=cccc, FirstName=fffffffff, emp_ID=222222, Age=25}
any idea how to fix the issue please or any better suggestion
Thank You in advance
Here is the code That I wrote
workbook = WorkbookFactory.create(inStream);
workSheet = workbook.getSheetAt(0);
DataFormatter df = new DataFormatter();
Map<String, String> myMap = new LinkedHashMap<>();
List<Map<String, String>> list = new ArrayList<>();
row = workSheet.getRow(0);
ArrayList<String> headersName = new ArrayList<String>();
for (int j = 0; j <= row.getPhysicalNumberOfCells(); j++) {
row.getCell(j);
if ((df.formatCellValue(row.getCell(j)).isEmpty())) {
continue;
} else {
headersName.add(df.formatCellValue(row.getCell(j)));
}
}
System.out.println(headersName);
OUTER: for (Row myrow : workSheet) {
for (int i = 0; i < myrow.getLastCellNum(); i++) {
if (myrow.getRowNum() == 0) {
continue OUTER;
}
String value = df.formatCellValue(myrow.getCell(i));
myMap.put(headersName.get(i), value);
}
list.add(myMap);
}
System.out.println(list.size());
for (Map<String, String> map : list) {
System.out.println(map);
}
the print of my list
{Name=cccc, FirstName=fffffffff, emp_ID=222222, Age=25}
{Name=cccc, FirstName=fffffffff, emp_ID=222222, Age=25}
The issue lies in myMap.put(headersName.get(i), value). In that line, if the key already exists in the map, it overrides it. But later on, list.add(myMap) passes a reference to the same map, not a new version of it. So on the second iteration, when the line overrides the value, it overrides it on the first map already in the list. See below for a basic example of the same issue.
import java.util.*;
public class Example {
public static void main(String []args) {
Map<String, String> myMap = new LinkedHashMap<>();
List<Map<String, String>> list = new ArrayList<>();
myMap.put("abc", "123");
list.add(myMap);
System.out.println(list.get(0));
myMap.put("abc", "234");
System.out.println(myMap);
System.out.println(list.get(0));
}
}
To fix it, look into deep copies so that changing one doesn't change them all.
In groovy the original value get overwritten when I change values in a clone list. Does anyone know if I am doing it wrong or it is a bug older groovy?
I am doing something like this:
List<Foo> myFooList = fooList.newFoos.findAll { it.type == "Types}
List<Foo> newFoo = fooList.oldFoos.findAll { it.type == "Types}.clone()
newFoo.each {
it.value = "neeeew value"
}
Foo fooOne = newFoo.each { foooo ->
fooTwo = fooList.oldFoos.find { it.id == foooo.id}
if(fooTwo.value != foooo.value) {
//Here it should go... but it turns out that fooTwo.value == foooo.value
}
}
the clone method called on list produces a new list but with the same objects in it.
you want to build new list with new objects. here is an example:
#groovy.transform.ToString
class Foo{
String type
String value
}
def fooList = [
new Foo(type:"Types", value:'old value1'),
new Foo(type:"Not", value:'old value2'),
new Foo(type:"Types", value:'old value3'),
new Foo(type:"Not", value:'old value4'),
]
def newFooList = fooList.
findAll{it.type=='Types'}.
collect{ new Foo(type:it.type, value:"new value") } //build new array with transformed elements
//check the original list
fooList.each{assert it.value!='new value'}
//check new list
newFooList.each{assert it.value=='new value'}
assert newFooList.size()==2
println fooList
println newFooList
I solved the issue by adding clone of the element as well, any way it became to much of cowboy fix:
List<Foo> myFooList = fooList.newFoos.findAll { it.type == "Types}
List<Foo> newFoo = fooList.oldFoos.findAll { it.type == "Types}.collect {it.clone()}
newFoo.each {
it.value = "neeeew value"
}
Foo fooOne = newFoo.each { foooo ->
fooTwo = fooList.oldFoos.find { it.id == foooo.id}
if(fooTwo.value != foooo.value) {
//Here it should go... but it turns out that fooTwo.value == foooo.value
}
}
public IEnumerable<CustomBo> FindBy(Expression<Func<CustomBo, bool>> predicate)
{
Mapper.CreateMap<Expression<Func<CustomBo, bool>>, Expression<Func<Entity, bool>>>();
var newPredicate = Mapper.Map<Expression<Func<Entity, bool>>>(predicate);
IQueryable<Entity> query = dbSet.Where(newPredicate);
Mapper.CreateMap<Entity,CustomBo>();
var searchResult = Mapper.Map<List<CustomBo>>(query);
return searchResult;
}
I want to map customBo type to Entity Type..
Here customBo is my model and Entity is Database entity from edmx.
I'm using AutoMapper.
I'm Getting following Error
Could not find type map from destination type Data.Customer to source type Model.CustomerBO. Use CreateMap to create a map from the source to destination types.
Could not find type map from destination type Data.Customer to source type Model.CustomerBO. Use CreateMap to create a map from the source to destination types.
Any Suggession what I'm missiong here..
Thanks
I find a work around. I create my custom methods to map Expression.
public static class MappingHelper
{
public static Expression<Func<TTo, bool>> ConvertExpression<TFrom, TTo>(this Expression<Func<TFrom, bool>> expr)
{
Dictionary<Expression, Expression> substitutues = new Dictionary<Expression, Expression>();
var oldParam = expr.Parameters[0];
var newParam = Expression.Parameter(typeof(TTo), oldParam.Name);
substitutues.Add(oldParam, newParam);
Expression body = ConvertNode(expr.Body, substitutues);
return Expression.Lambda<Func<TTo, bool>>(body, newParam);
}
static Expression ConvertNode(Expression node, IDictionary<Expression, Expression> subst)
{
if (node == null) return null;
if (subst.ContainsKey(node)) return subst[node];
switch (node.NodeType)
{
case ExpressionType.Constant:
return node;
case ExpressionType.MemberAccess:
{
var me = (MemberExpression)node;
var newNode = ConvertNode(me.Expression, subst);
MemberInfo info = null;
foreach (MemberInfo mi in newNode.Type.GetMembers())
{
if (mi.MemberType == MemberTypes.Property)
{
if (mi.Name.ToLower().Contains(me.Member.Name.ToLower()))
{
info = mi;
break;
}
}
}
return Expression.MakeMemberAccess(newNode, info);
}
case ExpressionType.AndAlso:
case ExpressionType.OrElse:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.Equal: /* will probably work for a range of common binary-expressions */
{
var be = (BinaryExpression)node;
return Expression.MakeBinary(be.NodeType, ConvertNode(be.Left, subst), ConvertNode(be.Right, subst), be.IsLiftedToNull, be.Method);
}
default:
throw new NotSupportedException(node.NodeType.ToString());
}
}
}
Now I'm calling it like
public CustomBo FindBy(Expression<Func<CustomBo, bool>> predicateId)
{
var newPredicate = predicateId.ConvertExpression<CustomBo, Entity>();
}
Still if anyone know how to do it by automapper then plz let me know.
Thanks
Looks like this was added after your asked your question: Expression Translation (UseAsDataSource)
Now all you have to do is dbSet.UseAsDataSource().For<CustomBo>().Where(expression).ToList();. Much nicer!
Map<Integer, Map<String, String>> Actions = new HashMap<Integer, Map<String, String>>();
Map<Integer, List<ActionName>> actionList = Service.getAvailableActionsById(order.id, user.id)
for(Map.Entry<Integer, List<ActionName>> entry : actionList)
{
Map<String, String> actionMap = new HashMap<String, String>();
for(ActionName actionName: entry.getValue()){
actionMap.put(actionName.name(), actionName.name());
}
Actions.put(entry.getKey(), actionMap);
}
--==// For the same functionality above I want to use map inject, while doing as below it unable to inject all the list values to map
Map<Integer, List<ActionName>> actionList = [:]
if ( order.id) actionList = Service.getAvailableActionsById(order.id, session.user.id)
Map Actions = actionList.inject( [:] ) { map, id, values -> map.put( id, values ); return map; }
--=====
Map availableActions = actionList.inject( [:] ) { map, key, listValue ->
map << [ (key) : listValue.collectEntries { [ it.name(), it.name() ] } ]
}
This should give what you are looking for, but I do not get the rationale behind doing this.
inject's closure takes to arguments: result and current element. If you want to call inject() on a map you should treat each element as a Map.Entry:
actionList.inject( [:] ) { map, elem ->
map[ elem.key ] = elem.value // key -> id, value -> values
map
}