I have following code. In the first i tried to set values in the list called 'unavailable'.
Next, in the for each I have to produce a cycle on the list domainStr minus unavailable. How can i do it?
public Result execute(List<String> domainsStr) {
Result result = new Result();
try {
List<String> domains = domainService.findByNames(domainsStr);
result.setUnavailable(domains);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
for (String domain : domainsStr) {
......
}
return result;
}
public static class Result {
private List<String> unavailable = new ArrayList<>();
public List<String> getUnavailable() {
return unavailable;
}
public void setUnavailable(List<String> unavailable) {
this.unavailable = unavailable;
}
}
removeAll(Collection c) is the function which would be the most helpful to you. Having said that, this will work properly only if you have the equals method correctly defined for your Domain object. In this case it is a String so it doesnt matter. But, just to keep it in mind.
so just say, domainsStr.removeAll(result.getUnavailable());
Also, if the Result class is static, why the new object creation here?
Result result = new Result();
This result.setUnavailable(domains);
can be changed to
Result.setUnavailable(domains);
I have to to produce a cycle on the list domainStr minus unavailable.
If I understood correctly, I think you are looking for the removeAll method :
Removes from this list all of its elements that are contained in the
specified collection (optional operation).
domainsStr.removeAll(result.getUnavailable());
for (String domain : domainsStr) {
}
If you want to let domainsStr unchanged, you can create a temporary list and perfom these operations on it.
List<String> tempList = new ArrayList<String>(domainsStr);
tempList.removeAll(result.getUnavailable());
for(String domain : tempList){
.....
I put them into a tempt list so you don't lose the items in the domainsStr list.
Related
I'm trying to find a data-structure in Java (or Groovy) that where something like this works:
MemberAdressableSetsSet mass = new MemberAdressableSetsSet();
mass.addSet(["a","b"]);
mass.addSet(["c","d","e"]);
mass.get("d").add("f");
String output = Arrays.toString(mass.get("e").toArray());
System.out.println(output); // [ "c", "d", "e", "f" ] (ordering irrelevant)
Does anything like that exist? And if not, is there a way to implement something like this with normal Java code that doesn't give the CPU or the memory nightmares for weeks?
Edit: more rigorously
MemberAdressableSetsSet mass = new MemberAdressableSetsSet();
Set<String> s1 = new HashSet<String>();
s1.add("a");
Set<String> s2 = new HashSet<String>();
s2.add("c");s2.add("d");s2.add("e");
mass.addSet(s1);
mass.addSet(s2);
Set<String> s3 = new HashSet<String>();
s3.add("a");s3.add("z");
mass.addSet(s3);
/* s3 contains "a", which is already in a subset of mass, so:
* Either
* - does nothing and returns false or throws Exception
* - deletes "a" from its previous subset before adding s3
* => possibly returns the old subset
* => deletes the old subset if that leaves it empty
* => maybe requires an optional parameter to be set
* - removes "a" from the new subset before adding it
* => possibly returns the new subset that was actually added
* => does not add the new subset if purging it of overlap leaves it empty
* => maybe requires an optional parameter to be set
* - merges all sets that would end up overlapping
* - adds it with no overlap checks, but get("a") returns an array of all sets containing it
*/
mass.get("d").add("f");
String output = Arrays.toString(mass.get("e").toArray());
System.out.println(output); // [ "c", "d", "e", "f" ] (ordering irrelevant)
mass.get("d") would return the Set<T> in mass that contains "d". Analogous to how get() works in, say, HashMap:
HashMap<String,LinkedList<Integer>> map = new HashMap<>();
LinkedList<Integer> list = new LinkedList<>();
list.add(9);
map.put("d",list);
map.get("d").add(4);
map.get("d"); // returns a LinkedList with contents [9,4]
The best I could come up with so far looks like this:
import java.util.HashMap;
import java.util.Set;
public class MemberAdressableSetsSet {
private int next_id = 1;
private HashMap<Object,Integer> members = new HashMap();
private HashMap<Integer,Set> sets = new HashMap();
public boolean addSet(Set s) {
if (s.size()==0) return false;
for (Object member : s) {
if (members.get(member)!=null) return false;
}
sets.put(next_id,s);
for (Object member : s) {
members.put(member,next_id);
}
next_id++;
return true;
}
public boolean deleteSet(Object member) {
Integer id = members.get(member);
if (id==null) return false;
Set set = sets.get(id);
for (Object m : set) {
members.remove(m);
}
sets.remove(id);
return true;
}
public boolean addToSet(Object member, Object addition) {
Integer id = members.get(member);
if (id==null) throw new IndexOutOfBoundsException();
if (members.get(addition)!=null) return false;
sets.get(id).add(addition);
members.put(addition,id);
return true;
}
public boolean removeFromSet(Object member) {
Integer id = members.get(member);
if (id==null) return false;
Set s = sets.get(id);
if (s.size()==1) sets.remove(id);
else s.remove(member);
members.remove(member);
return true;
}
public Set getSetClone(Object member) {
Integer id = members.get(member);
if (id==null) throw new IndexOutOfBoundsException();
Set copy = new java.util.HashSet(sets.get(id));
return copy;
}
}
Which has some drawbacks:
Sets are not directly accessible, which makes all Set methods and properties not exposed by explicitly defined translation methods inaccessible, unless the clones are an acceptable option
Type information is lost.
Say a Set<Date> is added.
It would not complain about trying to add, for example, a File object to that set.
At least the lost type information for the Sets doesn't extend to their members: the Set.contains() still works exactly as expected, despite both sides having been typecast to Object before being compared by contains(). So a set containing (Object)3 won't return true when asked whether it contains (Object)3L and vice versa, for example.
A set containing (Object)(new java.util.Date(10L)) will return true when asked whether it contains (Object)(new java.sql.Date(10L)) (and the other way round), but that's true even without the (Object) in front, so I guess that's "works as intended" ¯\_(ツ)_/¯
How often do you need to access by one element? Might be worth using a map and storing the same Set reference under multiple keys.
I would prevent external mutation to the map and sub sets, and provide helper method to do all of the updates:
public class MemberAdressableSets<T> {
Map<T, Set<T>> data = new HashMap<>();
public void addSet(Set<T> dataSet) {
if (dataSet.stream().anyMatch(data::containsKey)) {
throw Exception("Key already in member addressable data");
}
Set<T> protectedSet = new HashSet<>(dataSet);
dataSet.forEach(d -> data.put(d, protectedSet));
}
public void updateSet(T key, T... newData) {
Set<T> dataSet = data.get(key);
Arrays.stream(newData).forEach(dataSet::add);
Arrays.stream(newData).forEach(d -> data.put(d, dataSet));
}
public Set<T> get(T key) {
return Collections.unmodifiableSet(data.get(key));
}
}
Alternatively you could update the addSet and updateSet to create new Set instances if the key doesn't exist and make updateSet never throw. You'll also need to extend this class to handle the cases of merging sets. i.e. handle the use-case:
mass.addSet(["a","b"]);
mass.addSet(["a","c"]);
This solution allows for things like mass.get("d").add("f"); to affect the subset stored in mass, but with major drawbacks.
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
public class MemberAdressableSetsSetDirect {
private LinkedHashSet<Set> sets;
public void addSet(Set newSet) {
sets.add(newSet);
}
public Set removeSet(Object member) {
Iterator<Set> it = sets.iterator();
while (it.hasNext()) {
Set s = it.next();
if (s.contains(member)) {
it.remove();
return s;
}
}
return null;
}
public int removeSets(Object member) {
int removed = 0;
Iterator<Set> it = sets.iterator();
while (it.hasNext()) {
Set s = it.next();
if (s.contains(member)) {
it.remove();
removed++;
}
}
return removed;
}
public void deleteEmptySets() {
sets.removeIf(Set::isEmpty);
}
public Set get(Object member) {
for (Set s : sets) {
if (s.contains(member)) return s;
}
return null;
}
public Set[] getAll(Object member) {
LinkedHashSet<Set> results = new LinkedHashSet<>();
for (Set s : sets) {
if (s.contains(member)) results.add(s);
}
return (Set[]) results.toArray();
}
}
There's no built-in protection against overlap and thus we have unreliable access, as well as introducing the possibility of countless empty sets that need to be periodically purged with a manual call to deleteEmptySets(), as this solution can't detect if a subset was modified by direct access.
MemberAdressableSetsSetDirect massd = new MemberAdressableSetsSetDirect();
Set s1 = new HashSet();Set s2 = new HashSet();Set s3 = new HashSet();
s1.add("a");s1.add("b");
s2.add("c");s2.add("d");
s3.add("e");
massd.addSet(s1);massd.addSet(s2);
massd.get("c").add("a");
// massd.get("a") will now either return the Set ["a","b"] or the Set ["a","c","d"]
// (could be that my usage of a LinkedHashSet as the basis of massd
// at least makes it consistently return the set added first)
massd.get("e").remove("e");
// the third set is now empty, can't be accessed anymore,
// and massd has no clue about that until it's told to look for empty sets
massd.get("c").remove("d");
massd.get("c").remove("c");
// if LinkedHashSet makes this solution act as I suspected above,
// this makes the third subset inaccessible except via massd.getAll("a")[1]
Additionaly, this solution also can't preserve type information.
This will not even give warnings:
MemberAdressableSetsSetDirect massd = new MemberAdressableSetsSetDirect();
Set<Long> s = new HashSet<Long>();
s.add(3L);
massd.addSet(s);
massd.get(3L).add("someString");
// massd.get(3L) will now return a Set with contents [3L, "someString"]
I have a parallel stream because the task is really slow, I will paste the code below. The situation is this.
I have an arrayList, I need to do something with each object in that list (this is slow) and add the object to a temporal list, the process in the stream ends ok, I think, because I can see each object processed with logs.
When the stream ends, sometimes, the temporal list has n-1 objects or one as null.
Any idea?
With this sample code the errors are not happening, but the logic is the same but without the business logic.
public class SampleCode {
public List<SomeObject> example(List<SomeObject> someObjectList) {
List<SomeObject> someObjectListTemp = new ArrayList<>();
someObjectList.parallelStream().forEach(someObject -> {
List<ExtraData> extraDataList = getExtraData(someObject.getId());
if (extraDataList.isEmpty()) {
someObjectListTemp.add(someObject);
} else {
for (ExtraData extraData : extraDataList) {
SomeObject someObjectTemp = null;
someObjectTemp = (SomeObject) cloneObject(someObject);
if (extraData != null) {
someObjectTemp.setDate(extraData.getDate());
someObjectTemp.setData2(extraData.getData2());
}
if (someObjectTemp == null) {
System.out.println("Warning null object"); //I NEVER see this
}
someObjectListTemp.add(someObjectTemp);
System.out.println("Added object to list"); //I Always see this the same times as elements in original list
}
}
});
if (someObjectListTemp.size() < 3) {
System.out.println("Error: There should be at least 3 elements"); //Some times one object is missing in the list
}
for (SomeObject someObject : someObjectListTemp) {
if (someObject == null) {
System.out.println("Error: null element in list"); //Some times one object is null in the list
}
}
return someObjectListTemp;
}
Could you try to use the flatMap method instead of foreach?
flatMap takes a list of lists and put all their elements in a single list.
This way you do not use another ArrayList to store your temporary objects.
I feel that this might be the issue, because parallelStream is multi threading and ArrayList is not synchronised
List<SomeObject> someObjectListTemp = someObjectList.parallelStream()
.map(so -> processSomeObject(so)) // makes a stream of lists (Stream<List<SomeObject>>)
.flatMap(Collection::stream) // groups all the elements of all the lists in one stream (Stream<Someobject>)
.collect(Collectors.toList()); // transforms the stream into a list (List<SomeObject>)
And stick your code in a separate method processSomeObject which returns a list of SomeObject:
static List<SomeObject> processSomeObject(SomeObject someObject) {
List<ExtraData> extraDataList = getExtraData(someObject.getId());
List<SomeObject> someObjectListTemp = new ArrayList<>();
if (extraDataList.isEmpty()) {
someObjectListTemp.add(someObject);
} else {
for (ExtraData extraData : extraDataList) {
SomeObject someObjectTemp = (SomeObject) cloneObject(someObject);
if (extraData != null) {
someObjectTemp.setDate(extraData.getDate());
someObjectTemp.setData2(extraData.getData2());
}
someObjectListTemp.add(someObjectTemp);
System.out.println("Added object to list");
}
}
return someObjectListTemp;
}
A small example would be
public static void main(String[] args) {
List<Object> test = new ArrayList<>();
IntStream.range(0, 100000).parallel().forEach(i -> test.add(new Object()));
for(Object o : test) {
System.out.println(o.getClass());
}
}
i'ts because ArrayList is not threadsafe and the internal array gets screwed
Not sure how I can achieve this.
I have a object list, where it consists of multiple data example
ABC1231211
ABC1231111
ABC4562222
ABC4562456
Now I trying to seperate the list according to their code, which is 123 and 456, and add header and tailer to them. So my expected result would be
Head
ABC1231211
ABC1231111
Tail
Head2
ABC4562222
ABC4562456
Tail2
But the result I get is
Head
ABC1231211
Tail
Head
ABC1231111
Tail
Head2
ABC4562222
Tail2
Head2
ABC4562456
Tail2
Code
#Override
public List process(List<Detail> l) throws Exception {
for (Detail d : l) {
if (d.Code().equals("123")) {
list = generateS(d);
}
if (d.Code().equals("456")) {
list = generateR(d);
}
}
return list;
}
public List<String> generateS(Detail d) throws Exception {
try {
list.add(new HDR("Head").getHeader());
DetailL x = new DetailL();
x.setType(d.getType());
....
list.add(x.getDetail());
list.add(new TLR("Tail").getTailer());
} catch (Exception ex) {
throw new BatchException(DetailProcessor.class, ex);
}
return list;
}
Any help would be much appreciated
If you're using Java 8, you can use streams:
public void process(List<Detail> details) throws Exception {
Map<String, List<Detail>> byCode =
details.stream().collect(Collectors.groupingBy(Detail::getCode));
byCode.entrySet().stream().forEach(entry -> {
System.out.println(headerFromType(entry.getKey()));
entry.getValue().foreach(System.out::println);
System.out.println(tailFromType(entry.getKey()));
}
with headerFromType and tailFromType returning "Head"/"Head2" or "Tail"/"Tail2", depending on the given type.
You are generating a new head and tail for each element instead of adding to the already-generated list.
For each Detail, you should first check if the list exists, and if it doesn't, then call generateS or generateR as appropriate. If the list exists, you want to call e.g. sList.add(sList.size()-1, d.getDetail()). You'll of course want to replace the call d.getDetail() with the value that's supposed to go into the list or a method call that returns that value.
Then you probably want to use list.addAll(sList) to add the generated lists' contents to list.
Another solution is to generate the combined list on demand, and store the two lists separately. In that case, you would check if the corresponding list is null in the beginning of generateS or generateR, and initialize it if it is.
You create a new header and a new tail every time you call generateS or generateR but you should just create a new header once if you find a new code ( for example 123).
Solution: You collect your details into a list before you call generateS or generateR and put all the details from collected list into your DetailL.
Here is another implemetation that takes another approach:
private void go() {
List<String> list = new ArrayList<>();
list.add("ABC1231211");
list.add("ABC1231111");
list.add("ABC4562222");
list.add("ABC4562456");
String lastTag = null;
int startPos = 0;
for (int i = 0; i < list.size(); i++) {
String tag = list.get(i).substring(3, 6);
if (!tag.equals(lastTag) && lastTag != null) {
print(list.subList(startPos, i));
startPos = i;
}
lastTag = tag;
}
print(list.subList(startPos, list.size()));
}
private void print(List<String> list) {
System.out.println("Head");
for (String item : list) {
System.out.println(item);
}
System.out.println("Tail");
}
Simply "If you come accross an element with a different tag, print the previous sublist". (And print whatever is left at the end since that sublist's printout is not triggered by a new tag.)
I have a mapper method which takes list of entities called Claim iterates over them and maps to CompensationDTO and adds to list, but entity can contain lists of children entities which type is also Claim and those children can also contain list of Claims, so to iterate over them all is best to use recursion but i'm not sure how it should be written
private List<CompensationDTO> mapToDTO(List<Claims> claims) {
List<CompensationsDTO> compensations = new ArrayList<>();
if (claims.isEmpty()) {
return new ArrayList<>();
}
for (Claim claim : claims) {
CompensationDTO compensationDTO = new CompensationDTO();
compensationDTO.setId(claim.getId());
compensationDTO.setAmount(claim.getAmount());
compensationDTO.setType(claim.getType());
compensations.add(compensationDTO);
mapToDTO(claim.getChildrenClaims());
}
return compensations;
}
I understand that the base case should return empty list but i don't know where to put the recursive function call mapToDTO(claim.getChildrenClaims());
Did you try to add compansations.addAll()?:
private List<CompensationDTO> mapToDTO(List<Claims> claims) {
List<CompensationsDTO> compensations = new ArrayList<>();
if (claims.isEmpty()) {
return new ArrayList<>();
}
for (Claim claim : claims) {
CompensationDTO compensationDTO = new CompensationDTO();
compensationDTO.setId(claim.getId());
compensationDTO.setAmount(claim.getAmount());
compensationDTO.setType(claim.getType());
compensations.add(compensationDTO);
compensations.addAll(mapToDTO(claim.getChildrenClaims()));
}
return compensations;
}
mapToDTO returns List<CompensationDTO> and you need to add these elements to your local list.
List<CompensationDTO> rec = mapToDTO(claim.getChildrenClaims());
compensations.addAll(rec);
I need to use a data structure which can -
maintain the insertion order.
do not store any duplicates.
And I can easily get and remove first element from it efficiently.
Below is my code which uses LinkedList but it doesn't filter out any duplicates. And it has removeFirst() method which gets and remove the first element in a list.
public static LinkedList<String> getData(TypeEnum types) {
LinkedList<String> listOfPaths = new LinkedList<String>();
String prefix = types.equals(TypeEnum.PARTIAL) ? TypeEnum.PARTIAL.value() : TypeEnum.UNPARTIAL.value();
listOfPaths.add(prefix + LOCAL_PATH); // first element in the list is always LOCAL PATH
for (String path : REMOTE_PATH) {
listOfPaths.add(prefix + path);
}
return listOfPaths;
}
Below is how I am using getData method:
LinkedList<String> data = getData(types);
String local_path = data.removeFirst(); // this is my local path
// use local_path here
// now iterate all the remote path
for(String remotePath : data) {
// do something with remotePath
}
What are the options I have here which will be efficient? Does any other data structure can do the same thing by avoiding the duplicates. I know Set can do that, but Set doesn't have any removeFirst method and not sure whether it's a right structure to use here. Also, Can anyone provide an example as well.
You can make use of a LinkedHashSet (maintains insertion order). For instance, add the items first to this Set to filter out duplicates, then add all the items into the LinkedList:
public static LinkedList<String> getData(TypeEnum types) {
LinkedList<String> listOfPaths = new LinkedList<String>();
LinkedHashSet<String> uniques = new LinkedHashSet<String>();
String prefix = types.equals(TypeEnum.PARTIAL) ? TypeEnum.PARTIAL.value() : TypeEnum.UNPARTIAL.value();
uniques.add(prefix + LOCAL_PATH); // first element in the list is always LOCAL PATH
for (String path : REMOTE_PATH) {
uniques.add(prefix + path);
}
listOfPaths.addAll(uniques);
return listOfPaths;
}
This answer was fixed according to #copeg comments, thanks.
The solution could be to just simply extend the list add method by doing something like this:
public class MyList<E> extends LinkedList<E> {
#Override
public boolean add(int index, E element){
if(this.contains(element))return false;
return super.add(index,element);
}
}