So I have a LinkedHashSet , with values say a1, a2, , b, c1, c2
I want to replace, b with x , such that the order of x should be same as order of b.
One obvious way would be
private LinkedHashSet<String> orderedSubstitution(final Set<String> originalOrderedSet, final String oldItem,
final String newItem) {
final LinkedHashSet<String> newOrderedSet = new LinkedHashSet<String>();
// Things we do to maintain order in a linkedHashSet
for (final String stringItem : originalOrderedSet) {
if (stringItem.equals(oldItem)) {
newOrderedSet.add(newItem);
} else {
newOrderedSet.add(stringItem);
}
}
return newOrderedSet;
}
not only this is O(n) i also feel this is not the fastest way. Any better solution ?
NOTE : I HAVE TO use linkedHashMap.
One way to do it would be to use a subclass of LinkedHashSet that has the replacement built in, e.g.:
public class ReplacingLinkedHashSet extends LinkedHashSet<String> {
private final String what;
private final String with;
public ReplacingLinkedHashSet(String what, String with) {
this.what = what;
this.with = with;
}
#Override
public Iterator<String> iterator() {
final Iterator<String> iterator = super.iterator();
return new Iterator<String>() {
#Override
public boolean hasNext() {
return iterator.hasNext();
}
#Override
public String next() {
String next = iterator.next();
return what.equals(next) ? with : next;
}
#Override
public void remove() {
iterator.remove();
}
};
}
}
But that means the replacement would have to be known before you fill the Set.
(Of course you could easily turn this <String> version into a generic one.
Responding to comments:
OK, then there is no way to solve it without a full iteration. You could however just leave the LinkedHashSet untouched and decorate the iterator when retrieving the values.
Create a structure Map
Insert all the string with < String, OrderOfTheString>
Do the insertion of the new String by adding a small Delta after the current string's OrderOfTheString.
Convert Map to LikedHashSet
I know it is complicated but it is definately better when we have linked hash Map of ~1000000 elements and there are about 1000 elements to be inserted.
Related
I have an object list that retrieves multiple values from a database, like so:
List<Object> listRequest = daoManager.getLaptopsForRequest(BigInteger.valueOf(itemTransItem.getAssetType().getId()), BigInteger.valueOf(approverId));
The result of which looks like this (printed out on the console, via for each):
{asset_type_id=1, inventory_id=1, from_dt=2015-09-18 18:04:55.77, id=1, asset_id=1, status=1, thru_dt=null}
{asset_type_id=1, inventory_id=1, from_dt=2015-09-18 18:04:55.77, id=2, asset_id=2, status=1, thru_dt=null}
{asset_type_id=1, inventory_id=1, from_dt=2015-09-18 18:04:55.77, id=3, asset_id=3, status=1, thru_dt=null}
What's the quickest and/or most efficient way to get only the object where asset_id = 2, or an array of asset_id (1 and 2), and putting the results in another array?
I contemplated casting each object as a string, and then turning each string into an array (split by the comma), and then turning each item of the array into a further array (or a hashmap) by using the =, but that seems like a long, long, complex way of nested for loops that might fail (see comparing array of assets).
Perhaps there's another quicker / less complex way to do this that I'm missing? Any suggestions? Thanks.
EDIT: For reference, here's the getLaptopsForRequest function:
public List getLaptopsForRequest(BigInteger asset_type_id, BigInteger party_id){
SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(laptopsForRequestSql);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List forRequest = query.setBigInteger(0, asset_type_id).setBigInteger(1, party_id).list();
return forRequest;
}
It returns a list of the results of the query. As this code has been in place, I'm not allowed to edit it.
A quick and dirty solution would be to match each item against regex ^.*asset_id=([0-9]+).*$.
If what you're getting from that method is indeed a list of Strings containing those JSONs, you could create a model class and use a JSON serializer like GSON or Jackson to read the strings into Java objects, and then you could work with them.
What you are trying to do basically is to filter a list of objects. You could implement the Filter Pattern writing your own Iterator for the list.
Just extends this class to implement your own filter.
public abstract class Filter<T> {
public abstract boolean passes(T object);
public Iterator<T> filter(Iterator<T> iterator) {
return new FilterIterator(iterator);
}
public Iterable<T> filter(Iterable<T> iterable) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return filter(iterable.iterator());
}
};
}
private class FilterIterator implements Iterator<T> {
private Iterator<T> iterator;
private T next;
private FilterIterator(Iterator<T> iterator) {
this.iterator = iterator;
toNext();
}
public boolean hasNext() {
return next != null;
}
public T next() {
if (next == null)
throw new NoSuchElementException();
T returnValue = next;
toNext();
return returnValue;
}
public void remove() {
throw new UnsupportedOperationException();
}
private void toNext() {
next = null;
while (iterator.hasNext()) {
T item = iterator.next();
if (item != null && passes(item)) {
next = item;
break;
}
}
}
}
}
and then use it in this way:
List<MyObject> newList = new ArrayList<MyObject>();
for(MyObject obj : filter.filter(listObjs) ){
newList.add(obj);
}
Assuming your objects have getter et setter methods.
Only the object where asset_id = "2", asset_id here being a string
listRequest.stream().filter(e -> e.getAssetId() == "2" ).toArray();
I have a List in which I need to add a prefix in all the elements of my list.
Below is the way I am doing it by iterating the list and then adding it. Is there any other better way to do it? Any one-two liner that can do the same stuff?
private static final List<DataType> DATA_TYPE = getTypes();
public static LinkedList<String> getData(TypeFlow flow) {
LinkedList<String> paths = new LinkedList<String>();
for (DataType current : DATA_TYPE) {
paths.add(flow.value() + current.value());
}
return paths;
}
I need to return LinkedList since I am using some methods of LinkedList class like removeFirst.
I am on Java 7 as of now.
For one liners, use Java 8 Streams :
List<String> paths = DATA_TYPE.stream().map(c -> flow.value() + c.value()).collect(Collectors.toList());
If you must produce a LinkedList, you should use a different Collector.
Your implementation looks ok, but if you want something different, try this:
public static List<String> getData(final TypeFlow flow) {
return new AbstractList<String>() {
#Override
public String get(int index) {
return flow.value()+DATA_TYPE.get(index).value();
}
#Override
public int size() {
return DATA_TYPE.size();
}
};
}
This way you create a "virtual list" which does not actually contains data, but computes it on the fly.
I get a Deque<Element> deque and I want to transfer all the elements to the other structure: SortedSet<Element> sortedSet.
And the sequence of elements in sortedSet is just as same as the sequences in which the elements are popped from deque.
For example: if all the elements are popped from deque in a sequence: E01, E02, ..., E10.
The sequence of elements stored in sortedSet are also E01, E02, ..., E10.
I don't know how to override the comparator to let the elements store in such a sequence.
Do you know how to do that?
OK, this is most bizarre. You expect to have a SortedSet with elements in iteration order...
Here is a bizarre solution to this bizarre problem:
// final is CRITICAL here
final List<Element> list = new ArrayList<>(deque);
deque.clear();
final Comparator<Element> cmp = new Comparator<>()
{
#Override
public int compare(final Element a, final Element b)
{
return Integer.compare(list.indexOf(a), list.indexOf(b));
}
}
return new TreeSet<>(list, cmp);
HOWEVER: this will only work reliably if no two elements in the Deque are .equals()!
But this is the best you can do given the inherent incompatibility of requirements. All in all, I suspect a XY problem..
There is a way to make that reliable but this requires that you use Guava:
final Equivalence<Object> eq = Equivalence.identity();
final Function<Element, Equivalence.Wrapper<Object>> f = new Function<>()
{
#Override
public Equivalence.Wrapper<Object> apply(final Element input)
{
return eq.wrap(input);
}
}
final List<Element> list = Lists.newArrayList(deque);
deque.clear();
final List<Equivalence.Wrapper<Object>> wrapped = Lists.transform(list, f);
final Comparator<Element> cmp = new Comparator<>()
{
#Override
public int compare(final Element a, final Element b)
{
return Integer.compare(wrapped.indexOf(f(a)),
wrapped.indexOf(f(b)));
}
};
return new TreeSet<>(list, cmp);
As fge already stated, you need a LinkedHashSet, a collection which keeps the insertion order:
Set<Element> convertToSet(Deque<Element> dq)
{
LinkedHashSet<Element> lhs = new LinkedHashSet<Element>():
while(!dq.isEmpty())
{
lhs.add(dq.peekFirst());
}
return lhs;
}
Jane, I wrote a simple code:
public static void main(String[] args) {
SortedSet<Integer> set = new TreeSet<Integer>(new Comparator<Integer>() {
#Override
public int compare(Integer i1, Integer i2) {
return 1;
}
});
Deque<Integer> deq = new LinkedList<Integer>();
deq.add(5);
deq.add(1);
deq.add(3);
set.addAll(deq);
System.out.println(deq); // 5,1,3
}
The comparator should always return 1 this way the order stays the same, if this was your question.
Warning: this solution violates the Comparable and Set contract. Use it with caution.
ArrayList searchList = new ArrayList();
ArrayList words=(ArrayList) request.getSession().getAttribute("words");
words.add("one");
words.add("twenty one");
words.add("thirty one");
words.add("two");
words.add("twenty two");
words.add("thirty two");
words.add("three");
words.add("twenty three");
words.add("thirty three");'
If I have this arraylist and I want to search all the strings containing one(i.e. one,twenty one and thirty one), what logic should I use? Means how should I do that?
for (String item : searchList) {
if (item.contains("one") {
// Do something. Like adding the result to a different list.
// If you need the index from the original list, you a for instead of a for each
}
}
//iterate through words
for(String str : list){
//check if word contains the key
if(str.contains(key)){
//add its reference to another resultant list
result.add(str);
}
}
for (String word : words) {
if (word.contains("one")) {
//we have a match
}
}
Of course you have to loop thru the elements. Look for ways to loop thru an ArrayList: that can be indexed or with the
for (x : collect)
notation.
In the loop you have to do some pattern matching. Read String Java API doc for a method.
(Give'em some think food ...)
You could solve this using iterators if the condition will be more complex
public interface IPredicate<T> {
boolean check(T t);
}
public class PredicatIterable<T> implements Iterable<T> {
private final Iterator<T> iterator;
private final IPredicate<T> predicate;
public PredicatIterable(Iterable<T> iterable, IPredicate<T> predicate) {
this.iterator = iterable.iterator();
this.predicate = predicate;
}
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
T current;
#Override
public boolean hasNext() {
if(iterator.hasNext()) {
T next = iterator.next();
if(predicate.check(next)) {
current = next;
return true;
}
current = null;
}
return false;
}
#Override
public T next() {
return current;
}
#Override
public void remove() {
throw new RuntimeException("Invalid useage of method");
}
};
}
}
To validate more the single predicate you can create also method that is responsible for conuntion or alternative of two IPredicate argument.
In general, when searching an item in a List, the best solution is to sort your List first using Collections.sort() method. Then using the Collections.binarySearch() method, find your element.
In this case your elements are String type that are Comparable and can be sorted alphabetically otherwise you needed to implement Comparable interface for your element class type.
I am a newbie, I have a question.
I have a map. I have to loop through the map and build the iterator.
Example:
public Iterable<Test> getTests(Map<String, Test> testMap,
Set<String> strings)
{
//loop tru the set of strings and build iterator.
for(final String test1 : strings)
{
Test test = testMap.get(test1);
//build a iterator. not a list.
}
return iterator
}
How can I do this?
First of all, your method is returning an Iterable, not an Iterator. Map, Set, and List all implement Iterable, so it might be easier than you think.
Second, an Iterable is merely a class that has an iterator() method which returns an Iterator.
So I would simply build a List of the results and then return it. If you really want to return an Iterator, I would instead call iterator() on the list and return that.
Skipping over your Iterator/Iterable confusion (and Iterable is basically an Iterator factory... so you need to write an Iterator either way), I think you mean something like this:
Iterator<Test> getTests(final Map<String,Test> testMap, final Set<String> strings) {
return new Iterator<Test>() {
private final Iterator<String> keyIter = strings.iterator();
private String lastKey;
public boolean hasNext() { return keyIter.hasNext(); }
public Test next() { lastKey = keyIter.next(); return testMap.get(lastKey); }
public void remove() { testMap.remove(lastKey); }
};
}
And if you want to return an Iterable, well, that just has to be a factory for those:
Iterable<Test> getTests(final Map<String,Test> testMap, final Set<String> strings) {
return new Iterable<Test>() {
public Iterator<Test> iterator() {
return new Iterator<Test>() {
private final Iterator<String> keyIter = strings.iterator();
private String lastKey;
public boolean hasNext() { return keyIter.hasNext(); }
public Test next() { lastKey = keyIter.next(); return testMap.get(lastKey); }
public void remove() { testMap.remove(lastKey); }
};
}
};
}
For extra credit, you can parameterise this method itself and have a generic way of iterating over a selection from a map:
Map<String, Action> map;
Set<String> keys;
for (Action x : filterMap(map, keys)) {
}
Since Collection extends Iterable, the correct solution would be to add the tests to some sort of collection, like an ArrayList.
Collection<Test> tests = new ArrayList<Test>();
for (String key : strings) {
Test t = testMap.get(key);
if (t != null)
tests.add(t);
}
return tests;
If you want to really return Iterable simplest way is this
public Iterable<Test> getTests(Map<String, Test> testMap, Set<String> strings)
{
testMap = new HashMap<String, Test>(testMap);
testMap.keySet().retainAll(strings);
return testMap.values();
}
If you want to return an iterator, replace the last line with
return testMap.values().iterator();
If you don't care about modifications to the passed in map, skip the initial temp map construction.
EDIT:
removed use of clone on the Map interface which doesn't have it.
As a stab in the dark, what you may be looking for is Map.entrySet.iterator(). It allows you to iterate over the entries of the map.
Note: I know this is not an answer to the OP's question, but it's my guess at answering what they are actually looking for. If this guess turns out to be wrong, I'll delete this answer again to spare people the confusion.
An Iterable is something different from an Iterator. An Iterable is something you can iterate through, like a List. You use an Iterator for that. Your questions is not clear about what you want to return from getTests().
Your best shot would be to create an Iterable (like a List or Vector) and return that, or return its Iterator.