Removing common elements between two different Arraylist - java

I have read several posts for this but not getting the exact thing I am looking for. I know how to develop a complex logic for this, this is for Android and we can't expect too much processing on the device due to the limited resources available.
I have an ArrayList of an bean class objects consisting five fields as
Java Bean -- MyShares
fileName
filePath
fileSize
isShared
Creator
I have another ArrayList of String which contains only filepaths. Now what I want is to remove all the common elements between the two arraylist means the file paths in seconds arraylist and file path in first arraylist objects are similar then I have to remove from both of the arraylist but I don't want a new arraylist which contains the uncommon elements. But I want to get my both arraylist only without their common elements.

You could use a Map from String to your object type (I used Obj in order to make a SSCCE).
Assume we are given a list objects and a list strings.
Steps:
Put all objects in a map with their str variable as key
Get all those str variables using map.keySet()
Get all strings that are in objects but not in strings by keys.removeAll(strings)
Get all strings that are in strings but not in objects by strings.removeAll(keys)
Get the objects that correspond to the remaining keys
Note that you need to be careful in steps 3 and 4, because you need to back up one of the collections.
import java.util.*;
public class Test {
public static void main(String[] args) throws Exception {
new Test();
}
public Test() {
List<Obj> objects = new ArrayList<>();
objects.add(new Obj("a"));
objects.add(new Obj("b"));
objects.add(new Obj("c"));
List<String> strings = new ArrayList<>();
strings.add("a");
strings.add("d");
strings.add("e");
remove(objects, strings);
System.out.println(objects);
System.out.println(strings);
}
public void remove(List<Obj> objects, List<String> strings) {
Map<String, Obj> map = new HashMap<>();
for (Obj object : objects) {
map.put(object.str, object);
}
Set<String> keys = map.keySet();
List<String> oldStrings = new ArrayList<>(strings);
strings.removeAll(keys);
keys.removeAll(oldStrings);
objects.clear();
for (String key: keys) {
objects.add(map.get(key));
}
}
public class Obj {
public String str;
public Obj(String str) {
this.str = str;
}
#Override
public String toString() {
return str;
}
}
}
Prints:
[b, c]
[d, e]

Rough Java code:
HashSet<String> commonKeys = new HashSet();
for (Share share : shares) {
commonKeys.add(share.filePath);
}
commonKeys.retainAll(filePaths);
for (Iterator<Share> it = shares.iterator(); it.hasNext(); ) {
Share share = it.next();
if (commonKeys.contains(share.filePath)) {
it.remove();
}
}
filePaths.removeAll(commonKeys);
This won't be O(N) because remove on an ArrayList is expensive. To get O(N) behavior you either need to create new ArrayList instances, or add the elements you don't want removed to temporary lists, and then clear() and add them back into the original lists.

I will go with some clues for you
Suppose you have two lists one for bean objects namely myBeans and another for filePaths namely filePaths
List<MyBean> beansToRemove = new ArrayList<MyBean>();
List<FilePath> filePathsToRemove = new ArrayList<FilePath>();
for(Bean myBean : myBeans) {
for(FilePath filePath : filePaths) {
if(myBean.getfilePath.equals(filePath.getFilePath())) {
beansToRemove.add(myBean);
filePathsToRemove.add(filePath);
}
}
}
//Now remove filePaths and beans if any
for(Bean myBean : beansToRemove) {
myBeans.remove(myBean);
}
for(FilePath filePath : filePathsToRemove) {
filePaths.remove(filePath);
}
it is just a flow to make you clear for what to do; you can further customize it according to your needs.

You can use an outer loop to scan over the Bean objects, and an inner loop to scan over the file paths.
pseudo code:
for (Bean i in beans) {
for (String p in paths) {
if (i.path.equals(p)) {
beansToRemove.add(i);
pathsToRemove.add(p);
}
}
}
beans.removeAll(beansToRemove);
paths.removeAll(pathsToRemove);
I'm not sure if my extra arraylists to track the removed arraylists go against your question or not since the original arrays remain.
If you presort both arrays on the path and keep track of the position in each area (not exhaustive search) you can improve it from n2 to nlgn

Related

convert arrays of java objects in nested for loops to hashmap

I am working with two java objets. One of these object just have string attributes and the other one have strings and list of the first object.
The goal for me is to replace the double loops for a hasmap to reduce the time complexity. In this loop I do a equality check to see if some strings matches.
``
public class Object1 {
String name;
String xyz;
List<Object2> listObject2;
}
public class Object2 {
String name;
String abc;
String def;
}
Now in my main file I have the following function:
public fillNestedObject() {
List<Object1> listObject1 = new ArrayList();
listObject1 = fetchObjects1FromApi();
List<Object2> listObject2 = new ArrayList();
listObject2 = fetchObjectsFromApi2();
for(Object1 object1 : listObject1){
List<Object2> tmpList = new ArrayList();
for(Object2 object2 : listObject2) {
if(object1.getName().equals(object2.getName())){
tmpList.add(object2)
}
}
object1.setListObject2(tmpList)
}
}
I'm pretty sure that to reduce the time complexity I can replace my double for loops by a hasmap (or 2?) but I am not sure how to do this because I want the equality to be true.
I read that I should use stream to convert into hasmaps on other questions but I am not sure how streams are gonna be used to achieve what I want.
First the Object2 stream is reduced to a map of the list of items with the same name.
Then retrieve the object 1 items from collect.
Map<String, List<Object2>> reduced2 = Collections.unmodifiableMap(
stream2.reduce(new HashMap<>(), (a, b) -> {
if (!a.containsKey(b.getName())) {
a.put(b.getName(), new ArrayList<>());
}
a.get(b.getName()).add(b);
return a;
}, (a, b) -> b));
stream1.peek(object1 -> object1.setListObject2(reduced2.get(object1.getName())))
.collect(Collectors.toList());

How to output list of names in an object? Java

I have a function that I want to output a list of all the names in the object. What is the easiest way to do this?
Requirement object has a names variable and a method called getChildren which contains a list of Requirements.
Void updateItems(Requirement r)
{
System.out.println(r.getChildren.names) //doesnt work
}
I want to output all the names of the children objects like this:
Hello1, Hello2, Hello3
Requirement object has a names variable and a method called
getChildren which contains a list of Requirements.
the code below will retrieve the children's list for the current r object and iterate over its list in order to display their names.
void updateItems(Requirement r)
{
r.getChildren().forEach(c -> System.out.print(c.names+" "));
}
You mentioned "getChildren contains a list of Requirements". I guess you mean getChildren returns a list of Requirement objects?
If that's right. You could try:
void updateItems(Requirement r) {
for (Requirement child: r.getChildren()) {
System.out.println(child.names);
}
}
You said the method getChildren contains a list.
So you must iterate through the elements of the list to get the output:
First: Create a variable for your list.
ArrayList<String> x = new ArrayList<>();
Then you can call the getChildren method to save your list:
x = getChildren();
And then you can iterate through it.
for(String names : x){
System.out.println(names);
}
That means:
void updateItems(Requirement r)
{
ArrayList<String> x = new ArrayList<>();
x = r.getChildren();
for(String names : x){
System.out.println(names);
}
}

Java, get all variable values of a class

So I have a class called Test:
public class Test{
protected String name = "boy";
protected String mainAttack = "one";
protected String secAttack = "two";
protected String mainType"three";
protected String typeSpeak = "no spoken word in super class";
//Somehow put all the class variables in an Array of some sort
String[] allStrings = ??(all class' strings);
//(and if you feel challenged, put in ArrayList without type declared.
//So I could put in, not only Strings, but also ints etc.)
public void Tester(){
//Somehow loop through array(list) and print values (for-loop?)
}
}
As you can see, I want to put all the class variables in an Array or ArrayList (or something similar) automatically.
And next I want to be able to loop through the array and print/get the values.
Preferably using an enhanced-for loop.
As other said, don't do this. But this is how:
Class<?> cl = this.getClass();
List<Object> allObjects = new ArrayList<Object>();
for (java.lang.reflect.Field f: cl.getDeclaredFields())
{
f.setAccessible(true);
try
{
Object o = f.get(this);
allObjects.add(o);
}
catch (Exception e)
{
...
}
}
for (Object o: allObjects)
System.out.println(o);
If you really really need do this you need to use Reflection.
However a much better approach would be to store the values in a Map (probably a HashMap) and then you can query/set/etc them from that easily.
You can use Map or Hashmap to store variables and its values instead of Array or Arraylist
HashMap is an object that stores both “key/value” as a pairs. In this article, we show you how to create a HashMap instance and iterates the HashMap data.
Why not use a HashMap for the values and iterate through that?
Iterate through a HashMap
Do this.
String threeEleves = "sky";
String sevenDwarves = "stone";
String nineMortal = "die";
String oneRing[] = new String[] // <<< This
{
threeElves,
sevenDwarves,
nineMortal
}
or do this
// in some class.
public void process(final String... varArgs)
{
for (String current : varArgs)
{
}
}
String one = "noodles";
String two = "get";
String three = "in";
String four = "my";
String five = "belly";
process (one, two, three, four, five);

removing duplicates from list of lists and preserving lists

I have an arrayList of arrayLists. Each inner arraylist contains some objects with the format (name.version) .
{ {a.1,b.2,c.3} , {a.2,d.1,e.1} , {b.3,f.1,z.1}....}
For example a.1 implies name = a and version is 1.
So i want to eliminate duplicates in this arraylist of lists. For me , two objects are duplicate when they have the same name
So essentially my output should be
{ { a.1,b.2,c.3},{d.1,e.1} ,{f.1 ,z.1} }
Note that i want the output in the exact same form (That is , i dont want a single list with no duplicates)
Can someone provide me with an optimal solution for this?
I can loop through each inner list and place the contents in the hashset. But two issues there, i cant get back the answer in
form of list of lists.Another issue is that when i need to override equals for that object , but i am not sure if that would
break other code. These objects are meaningfully equal if their names are same (only in this case. I am not sure that would
cover the entire spectrum)
Thanks
I used Iterator.remove() to modify the collection as you move through it.
// build your example input as ArrayList<ArrayList<String>>
String[][] tmp = { { "a.1", "b.2", "c.3" }, { "a.2", "d.1", "e.1" },
{ "b.3", "f.1", "z.1" } };
List<List<String>> test = new ArrayList<List<String>>();
for (String[] array : tmp) {
test.add(new ArrayList<String>(Arrays.asList(array)));
}
// keep track of elements we've already seen
Set<String> nameCache = new HashSet<String>();
// iterate and remove if seen before
for (List<String> list : test) {
for (Iterator<String> it = list.iterator(); it.hasNext();) {
String element = it.next();
String name = element.split("\\.")[0];
if (nameCache.contains(name)) {
it.remove();
} else {
nameCache.add(name);
}
}
}
System.out.println(test);
Output
[[a.1, b.2, c.3], [d.1, e.1], [f.1, z.1]]
List<List<Pair>> inputs; // in whatever format you have them
List<List<Pair>> uniqued = new ArrayList<>(); // output to here
Set<String> seen = new HashSet<String>();
for (List<Pair> list : inputs) {
List<Pair> output = new ArrayList<>();
for (Pair p : list)
if (seen.add(p.getName()))
output.add(p);
uniqued.add(output);
}
Create a Set. Iterate over the list of lists' items. See if the item is in the Set. If it is already there, ignore it. If it isn't, add it to the Set and the list of lists.
Your method will return a new list of lists, not modify the old one. Modifying a list while iterating over it is a pain.

Issue iterating through ArrayLists

I have two questions. I have an object here that is of type ArrayList, and for this case let's call it "Car".
I have made 2 of them:
Car car1 = new Car();
Car car2 = new Car();
I have a function to add items to those Car objects:
car1.addPart("Front Wheels");
car1.addPart("Rear Wheels");
car1.addPart("Rear View Mirror");
car2.addPart("Rims");
car2.addPart("Steering Wheel");
car2.addPart("Bumper");
I need to have a function called sameContents() that I can call on car1:
car1.sameContents(car2);
which passes in an object of type ArrayList and checks it with car1 to see if they have the same contents and in the same order.
public boolean sameContents(Car c) {
ArrayList<String> other_car = c; // error: Type mismatch:
// cannot convert from Car to ArrayList<String>
for (String c : this.parts) {
System.out.println(c);
for(String oc : other_car) {
// stuff
}
}
}
I seem to be having all sorts of issues with this one. I can't get the other_car variable to be used in a foreach loop.
The second one that needs to be done is transferContents.
It's called like:
car1.transferContents(car2);
which transfers the items in car2 into car1 and then leaves car2 empty. I can't seem to get the ArrayList to work again in a foreach loop which is what I think I need.
public void transfer(Car c) {
// code for transfer method.
// this.parts is the arraylist of car parts
for (Car c: c) {
this.parts.add(c);
}
// not sure how to set car2 to empty...
}
Given some List<T> foo, foreach loops, e.g.:
for(T item : foo){
// body
}
are just a shorthand syntax for this idiom:
Iterator<T> iter = foo.iterator();
while(iter.hasNext()){
T item = iter.next();
// body
}
To check that there are more items in the list, you call iter.hasNext(), to retrieve the next item, you call iter.next().
Walking two lists can be done by keeping around 2 iterators, checking that both iterators have more elements, and then retrieving those elements. We can eliminate some boundary conditions on different length lists by realizing that different length lists cannot contain the same elements (since one list has more than the other).
From your description, it sounds like Car contains a property List<String> parts;, so we can formulate a solution as:
// different sizes, can't be equal
if(this.parts.size() != other.parts.size()){
return false;
}
// get iterators
Iterator<String> left = this.parts.iterator();
Iterator<String> right = other.parts.iterator();
// safe to only check `left` because the lists are the same size
while(left.hasNext()){
// check if left part is equal to the right part
if(!left.next().equals(right.next())){
// values are different, know at this
// point they're not equal
return false;
}
}
// at this point, have exactly the same values
// in the same order.
return true;
As for your transferContents method, you have the right idea, but you cannot iterate over the Car, you need to iterate over the List<String> parts. To remove individual parts, you can use remove() method, called like the add method, or to remove all elements, you can call clear()
Putting this together:
for (String part : c.parts) {
this.parts.add(part);
}
c.parts.clear();
You can rely on the java api to do all that you need.
The ArrayList equals method checks for order while comparing two lists.
You can use the removeAll() and addAll() methods to transfer contents.
public class Car {
private final List<String> parts = new ArrayList<String>();
public void addPart(String p) {
parts.add(p);
}
public boolean sameContents(Car c) {
return this.parts.equals(c.parts);
}
public void transfer(Car c) {
final List<String> temp = new ArrayList<String>(c.parts);
temp.removeAll(this.parts);
this.parts.addAll(temp);
c.parts.clear();
}
}
Your car should not be an array list, but have one. E.g. something like this:
class Car {
ArrayList<String> parts;
// ...
}
Then your sameContents method can simply call the lists's .equals() method to do the comparison:
public boolean sameParts(Car other) {
return this.parts.equals(other.parts);
}
Similarly, for transferring parts from another car, use the methods of the Lists to add the parts to your list, and then clear the other list.

Categories