Elegant way to copy properties from object to another
Automapper has been out there since ages ago. Tried and tested. http://automapper.org/
Here's an example:
using System;
using AutoMapper;
public class Program
{
class SupplierInfo
{
public SupplierInfo( string name, string shortName, string brandName ) {
Name = name;
ShortName = shortName;
BrandName = brandName;
}
public string Name {get; private set; }
public string ShortName {get; private set; }
public string BrandName {get; private set; }
}
class Supplier
{
public string name {get; set; }
public string shortName {get; set; }
public string brandName {get; set; }
}
public static void Main()
{
var dto = new Supplier() {
name = "Name 1",
shortName = "Short Name 1",
brandName = "Brand Name 1"
};
//From the tutorial:
//You only need one MapperConfiguration instance typically per AppDomain and should be instantiated during startup.
var config = new MapperConfiguration(cfg => cfg.CreateMap<Supplier, SupplierInfo>());
var mapper = config.CreateMapper();
SupplierInfo info = mapper.Map<SupplierInfo>(dto);
Console.WriteLine( info.Name );
Console.WriteLine( info.ShortName );
Console.WriteLine( info.BrandName );
}
}
The official Getting Started guide can be found at https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
Is there a pattern for using DTO's without having to duplicate the domain object's properties?
You could use an interface exposing only your object's data, without any domain methods. You'd still need to maintain two classes, but that would be a lot easier since most of the changes could be refactored by your IDE (Eclipse for example). Here's an example:
public interface PersonView {
String getFirstName();
String setFirstName();
}
public void Person implements PersonView {
private String firstName;
@Override // This annotation guarantees the interface is correct
public String getFirstName() {
return firstName;
}
...domain methods...
}
Is not a perfect solution, but it's a pretty clean one.
As for the problem itself, I for one don't really mind exposing the whole object to the view layer. IMHO, I don't think hiding some methods is worth the overhead. The team should have the discipline to use the objects wisely, but that's just my opinion.
JAVA - How to copy attributes of an object to another object having the same attributes?
To expand on my comment:
Using Dozer it can be as easy as:
Mapper mapper = new DozerBeanMapper();
ObjectA source = new ObjectA();
ObjectB target = mapper.map(source , ObjectB.class);
or if your target class doesn't have a no-arg constructor:
ObjectA source = new ObjectA();
ObjectB target = new ObjectB(/*args*/);
mapper.map(source, target );
From the Documentation (emphasis by me):
After performing the Dozer mapping, the result will be a new instance of the destination object that contains values for all fields that have the same field name as the source object. If any of the mapped attributes are of different data types, the Dozer mapping engine will automatically perform data type conversion.
Best Practice (Design Pattern) for copying and augmenting Objects
I think you are looking for Design Pattern Adapter
It's really just wrapping an instance of class A in an instance of class B, to provide a different way of using it / different type.
"I think" because you mention copying issues, so it may not be as much a class/type thing as a persistence / transmission thing.
Depending on your situation you may also be interested in dynamic proxying, but that's a Java feature.
How to efficiently return the max possible integer with a given number of digits
You have just 8 valid answers, so you can hardcode them:
private static int[] s_Numbers = {
0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999};
private static int largestPossibleNumber(int n) {
return s_Numbers[n];
}
Efficient algorithm to get the largest possible number by inserting a single digit
Can't you simplify to something like this:
def get_largest_insertion(long_n,n):
sn=str(abs(long_n))
n=str(n)
sign='-' if long_n<0 else '+'
return(max(int(sign+sn[0:i]+n+sn[i:]) for i in range(len(sn)+1)))
>>> get_largest_insertion(623, 5)
6523
>>> get_largest_insertion(-482,5)
-4582
>>> get_largest_insertion(666,5)
6665
OK, let's make it faster
With simple inspection, I believe it is true that if the number is negative, the insertion will always be one of:
- End of the string (such as
f(-524242, 8): -5242428)
; OR - Left of the first larger digit (such as
f(-3251342,2): -23251342
orf(-1251342,2): -12251342
And for a positive number:
- End of the string (such as
f(345342,2): 3453422)
; OR - Left of the first smaller digit (such as
f(3251342,2): 32521342
You can modify my function so that it finds that insertion point in one go with:
def f3(long_n, n):
sn=str(abs(long_n))
sign='-' if long_n<0 else '+'
n=str(n)
if sign=='-':
i=next((i for i,c in enumerate(sn) if c>n), len(sn))
else:
i=next((i for i,c in enumerate(sn) if c<n), len(sn))
return int(sign+sn[0:i]+n+sn[i:])
Now let's benchmark with this:
# your original function is f1
# my original is f2
# new one is f3
import time
# ====================
def attachRest(list_int, str_num, index):
s = [str(i) for i in list_int]
str_num = str_num[index:]
s = s + list(str_num)
num = int("".join(s))
return num
def f1(num, numInsertion):
new_num = []
isNumberInserted = False
if num > 0:
str_num = str(num)
for index, digit in enumerate(str_num):
if numInsertion > int(digit):
new_num.append(numInsertion)
num = attachRest(new_num, str_num, index)
isNumberInserted = True
break
else:
new_num.append(int(digit))
if isNumberInserted is False:
num = num * 10 + numInsertion
return num
else:
str_num = str(-1 * num)
for index, digit in enumerate(str_num):
if numInsertion < int(digit):
new_num.append(numInsertion)
num = attachRest(new_num, str_num, index)
isNumberInserted = True
break
else:
new_num.append(int(digit))
if isNumberInserted is False:
num = num*10 - numInsertion
return num
else:
return -1 * num
# ===============
def f2(long_n,n):
sn=str(abs(long_n))
n=str(n)
sign='-' if long_n<0 else '+'
return(max([int(sign+sn[0:i]+n+sn[i:]) for i in range(len(sn)+1)]))
def f3(long_n, n):
sn=str(abs(long_n))
sign='-' if long_n<0 else '+'
n=str(n)
if sign=='-':
i=next((i for i,c in enumerate(sn) if c>n), len(sn))
else:
i=next((i for i,c in enumerate(sn) if c<n), len(sn))
return int(sign+sn[0:i]+n+sn[i:])
# =====
def cmpthese(funcs, args=(), cnt=100, rate=True, micro=True, deepcopy=True):
from copy import deepcopy
"""Generate a Perl style function benchmark"""
def pprint_table(table):
"""Perl style table output"""
def format_field(field, fmt='{:,.0f}'):
if type(field) is str: return field
if type(field) is tuple: return field[1].format(field[0])
return fmt.format(field)
def get_max_col_w(table, index):
return max([len(format_field(row[index])) for row in table])
col_paddings=[get_max_col_w(table, i) for i in range(len(table[0]))]
for i,row in enumerate(table):
# left col
row_tab=[row[0].ljust(col_paddings[0])]
# rest of the cols
row_tab+=[format_field(row[j]).rjust(col_paddings[j]) for j in range(1,len(row))]
print(' '.join(row_tab))
results={}
for i in range(cnt):
for f in funcs:
if args:
local_args=deepcopy(args)
start=time.perf_counter_ns()
f(*local_args)
stop=time.perf_counter_ns()
results.setdefault(f.__name__, []).append(stop-start)
results={k:float(sum(v))/len(v) for k,v in results.items()}
fastest=sorted(results,key=results.get, reverse=True)
table=[['']]
if rate: table[0].append('rate/sec')
if micro: table[0].append('\u03bcsec/pass')
table[0].extend(fastest)
for e in fastest:
tmp=[e]
if rate:
tmp.append('{:,}'.format(int(round(float(cnt)*1000000.0/results[e]))))
if micro:
tmp.append('{:,.1f}'.format(results[e]/float(cnt)))
for x in fastest:
if x==e: tmp.append('--')
else: tmp.append('{:.1%}'.format((results[x]-results[e])/results[e]))
table.append(tmp)
pprint_table(table)
if __name__=='__main__':
import sys
import time
print(sys.version)
funcs=[f1, f2, f3]
cases=(
(-524242,8),
(345342,2),
(-34734573524242,8),
(71347345345342, 2)
)
for ln, n in cases:
for f in funcs:
print(f'{f.__name__}{ln, n}: {f(ln,n)}')
args=(ln, n)
cmpthese(funcs,args)
print()
That benchmark prints:
3.9.0 (default, Nov 21 2020, 14:55:42)
[Clang 12.0.0 (clang-1200.0.32.27)]
f1(-524242, 8): -5242428
f2(-524242, 8): -5242428
f3(-524242, 8): -5242428
rate/sec μsec/pass f2 f1 f3
f2 19,777 50.6 -- -37.0% -57.1%
f1 31,402 31.8 58.8% -- -32.0%
f3 46,148 21.7 133.3% 47.0% --
f1(345342, 2): 3453422
f2(345342, 2): 3453422
f3(345342, 2): 3453422
rate/sec μsec/pass f2 f1 f3
f2 19,671 50.8 -- -38.4% -56.5%
f1 31,916 31.3 62.2% -- -29.5%
f3 45,260 22.1 130.1% 41.8% --
f1(-34734573524242, 8): -347345735242428
f2(-34734573524242, 8): -347345735242428
f3(-34734573524242, 8): -347345735242428
rate/sec μsec/pass f2 f1 f3
f2 10,331 96.8 -- -38.1% -72.6%
f1 16,689 59.9 61.5% -- -55.7%
f3 37,679 26.5 264.7% 125.8% --
f1(71347345345342, 2): 721347345345342
f2(71347345345342, 2): 721347345345342
f3(71347345345342, 2): 721347345345342
rate/sec μsec/pass f2 f1 f3
f2 10,579 94.5 -- -67.7% -77.4%
f1 32,779 30.5 209.8% -- -29.9%
f3 46,743 21.4 341.8% 42.6% --
So same approach but inspection vs brute force makes it 2x to 3x faster...
Related Topics
Method Does Not Override Method from Its Superclass . Android Fragment
How to Check Heap Usage of a Running Jvm from the Command Line
How to Avoid Thread.Sleep in Unit Tests
Spring Boot API Call With Multiple @Requestparam
Java.Io.Filenotfoundexception: the System Cannot Find the File Specified
Refactor Multiple If' Statements in Java-8
How to Get the Path of Src/Test/Resources Directory in Junit
Java Program to Find Palindrome Numbers in Given Range
How to Save a File Downloaded With Httpclient into a Specific Folder
Spring Boot @Autowired Environment Throws Nullpointerexception
Java Properties - How to Create Dynamic Properties
Springboot - How to Start Embedded Container
Server_Error: [Code] 1675030 [Message]: Error Performing Query
Several Ports (8005, 8080, 8009) Required by Tomcat Server At Localhost Are Already in Use
How to Find Out My MySQL Url, Host, Port and Username
How to Get My Loops to Display Horizontally Instead of Vertically