so I have a set named "all" that contains objects Doc. Then I have another set called "partDocs" that contains other sets that contains Doc. Let's say that "all" contains = [Doc1, Doc2, Doc3]. I want partDocs to contain those sets like: [[Doc1], [Doc2], [Doc3]]. How can I do that?
I tried
Set<Doc> all = new HashSet<Doc>(); // contains [Doc1, Doc2, Doc3]
Set<Set<Doc>> partDocs = new HashSet<Set<Doc>>();
Set<Doc> set2 = new HashSet<Doc>();
for (i = 0; i < all.size(); i++) {
set2.clear();
set2.add(all.stream().toList().get(i)); // adds the i.th element of the all set
partDocs.add(set2);
}
However when I do this, partDocs only has the last element of the all set, because set2 is always changing, and its last value is [Doc3]
I also tried doing below, but its syntax is wrong
for (i = 0; i < all.size(); i++) {
partDocs.add(Set<allDocuments.stream().toList().get(i)>);
}
Does anyone have any idea about how to implement this?
I don't know if you actually want to do this. It seems like very confusing code but try the following:
Set<Set<Doc>> partDocs = new HashSet<Set<Doc>>();
Set<Doc> all = new HashSet<>();
for(Doc doc : all) {
partDocs.add(Set.of(doc));
}
And now you have a set (partDocs) that contains sets which contain docs
The invalidation of set2 is flawed.
Instead of
set2.clear();
it should be
set2 = new HashSet<Doc>();
This particular bug may be easier to understand if we use a list for partDocs
List<Set<Doc>> partDocs = new ArrayList<Set<Doc>>();
which results in
[[Doc3], [Doc3], [Doc3]]
Essentially, we are adding the same Set to the List and since we are using the same reference, consecutive calls to set2.clear() and set2.add() will affect both the local variable and the Set in the List.
Going back to partDocs being a Set, it will end up with only one entry, because a Set guarantees to not contain duplicate values and three identical instances are of course duplicates.
So, to fix this bug, we must ensure that the three objects added to partDocs are truly distinct, which is accomplished (partly) by the new invalidation routine
set2 = new HashSet<Doc>();
and otherwise by the fact that we add a different element to it each time.
Related
I'm trying to add, delete and edit the Slang (for example the key is: 3, it has a value of cute).
I have to use Java Swing. I have to use Java extra Swing. Because working with many classes at the same time, the variable that stores the [key, value] I set the variable static.
private static Map<String, ArrayList<String>> multiMap = new HashMap<String, ArrayList<String>>();
I have the operation that is adding 1 data slang. If it matches, it will add value to the existing slang.
I noticed, if you add a slang, it means adding a pair of [key, value], then when you find that pair of [key, value], you will find it. When adding value to the existing slang, I could not find it.
I'm guessing that since multiMap is static and ArrayList is not static if we only change the value of ArrayList, when accessed elsewhere it will not be updated. So in case of entering the same key, I choose to delete the old key and add a new one.
String[] valueStrings = null;
if(value.length() > 0){
valueStrings = value.split("[|]");
for(int i = 0; i <valueStrings.length; i++){
valueStrings[i] = valueStrings[i].trim();
}
}
if(choose == 0){ // 0 it mean new
Slang.multiMap.put(NewSlangs, new ArrayList<>());
Slang.multiMap.get(NewSlangs).addAll(Arrays.asList(valueStrings));
}
else if(choose == 2){ // 2 it mean old
ArrayList<String> tempArrayList = new ArrayList<>();
tempArrayList.addAll(multiMap.get(NewSlangs));
tempArrayList.addAll(Arrays.asList(valueStrings));
Slang.multiMap.remove(NewSlangs);
Slang.multiMap.put(NewSlangs, tempArrayList);
}
After an error is added to the new key, value, when looking again, it will be found. But not with inserting value. So I debug and have some problems here.
When adding new Array List
The new ArrayList address I added is# 1893 and I found it using the search function
When adding value
, error.
The old ArrayList contains old values with the address # 2050
image
The new ArrayList contains new values whose address is # 2088
But when looking for it, it only contains the old 4 values
image
image
and its address is also different.
So I am asking why and how to fix it?
Your code seems to be unnecessarily complex. I suggest simplifying it and then coming up with a simple example that demonstrates the problem you are having. A simple implementation of a multi-map would look like:
for (String strValue: value.split("|")) {
multimap.computeIfAbsent(key, k -> new ArrayList<>()).add(strValue.trim());
}
There is no need to create temporary lists nor to remove a map entry before adding a new value for the same key.
I ran into a seemingly simple problem that I haven't been able to figure out. Basically, my list holds a number of ints which represent different items, which works fine, but I need to be able to check if the list contains the same integer more than once and then remove them from the list.
if (myList.contains(100)) { // I want to check if the int '100' exists in myList twice
myList.remove(new Integer(100)); // I want to remove the 2 aforementioned duplicate integers
}
Apologies if my explanation wasn't the clearest. Thanks in advance!
EDIT: To clarify, I want the list to contain duplicates but I want to be able to check if the duplicate exists X times and then remove those instances from the list.
i.e.
I might want to add the int 100 7 times, and then later check if it exists twice and then remove 2 instances of it from the list only.
you can create a method to accomplish the task at hand, something along the lines of this:
private static boolean removeSpecfiedNumber(int number,int numberOfTimes, List<Integer> integerList){
if(integerList.stream().filter(x -> x == number).count() >= numberOfTimes){
for (int i = 0; i < numberOfTimes; i++) {
integerList.remove((Integer)number);
}
return true;
}
return false;
}
The parameter number is the number you want to check its occurrences i.e. 100 in your case.
The parameter numberOfTimes is the number of times you want to remove that element from the list.
The parameter integerList is, of course, the list you want to remove the elements from.
Let's take the code below as an example:
List<Integer> myList = new ArrayList<>();
myList.add(100);
myList.add(200);
myList.add(100);
myList.add(100);
myList.add(100);
myList.add(100);
myList.add(100);
myList.add(100);
removeSpecfiedNumber(100,2,myList);
System.out.println(myList);
this will remove 100 twice from myList and should, therefore, yield the elements below:
[200, 100, 100, 100, 100, 100]
The method return type can be void if you want, However, the return type of boolean can come in handy at times hence I've used that approach.
Also, you need not use the static modifier if you're dealing with objects, therefore you can remove it.
1) myList.remove(new Integer(100)); will remove only the first occurrence that is equals to 100.
You should loop on remove() while the list contains still an object with the same value.
2) To know if the list contains more than once the object, you could use indexOf() and lastIndexOf() .
If these are distinct, it means that you have more than one element.
So according to your requirement, you can remove all of them with the method described in the point 1.
Integer valueToCheck = 100;
if ( myList.indexOf(valueToCheck) != myList.lastIndexOf(valueToCheck) ) {
while (myList.contains(valueToCheck)){
myList.remove(valueToCheck);
}
}
You can use a Set which does not allowed duplicate keys e.g.
Set<Ineger> foo = new HashSet<>(myList);
And you can create a new List from that or use it as it is.
Starting java 8 you can use java stream api in such way:
List<Integer> i = new ArrayList<Integer>();
i.add(1);
i.add(2);
i.add(3);
i.add(1);
List<Integer> collect = i.stream().distinct().collect(Collectors.toList());
NOTE: new list will be created.
Is it possible to add items dynamically to a RDFList in Jena?
Something like:
RDFList list = model.createList(new RDFNode[] {});
//string with names of rdf classes
String[] parts = list.split("-");
for(int i = 0; i<parts.length; i++){
OntClass oclass = model.getOntClass("http://example.org/"+parts[i]);
list.add(oclass);
}
I'm getting
com.hp.hpl.jena.rdf.model.EmptyListUpdateException: Attempt to add() to the empty list (rdf:nil)
Thanks in advance
Without seeing all of your code and what some of the values are, we can't be sure what's happening, but I think the problem here is that you can't use RDFList#add with an empty list, and I think that's what you're creating at the start. Since you're creating a list with no elements, you should be getting rdf:nil back, which is the empty list. Note that the documentation for RDFList#add says:
If this list is the empty (nil) list, we cannot perform a side-effecting update without changing the URI of this node (from rdf:nil) to a blank-node for the new list cell) without violating a Jena invariant. Therefore, this update operation will throw an exception if an attempt is made to add to the nil list. Safe ways to add to an empty list include with(RDFNode) and cons(RDFNode).
You didn't mention whether you're getting that exception or not.
In your case, I think the easiest thing to do would be to create the array of OntClasses, and then just create the list from them. That is, you could do something like (untested):
String[] parts = list.split("-");
RDFNode[] elements = new RDFNode[parts.length];
for(int i = 0; i<parts.length; i++){
elements[i] = model.getOntClass("http://example.org/"+parts[i]);
}
RDFList list = model.createList(elements);
Alternatively, if you want to use with, as mentioned in the documentation, you'd do something like (again, untested):
RDFList list = model.createList(new RDFNode[] {});
//string with names of rdf classes
String[] parts = list.split("-");
for(int i = 0; i<parts.length; i++){
OntClass oclass = model.getOntClass("http://example.org/"+parts[i]);
list = list.with(oclass);
}
For a bit more about this, you might find this answer of mine and the comments on it relevant. You're not the first one to have had a bit of a struggle with RDFLists.
I have multiple ArrayList<String>s "linked" into a custom adapter I'm using to build a list view.
Now suppose they are just two in total, to simplify.
I want to sort one of them and then have this new order reflected into the other one, in order to maintain the list consistent.
This is what I was thinking to do and doesn't work, ending with an IndexOutOfBoundsException: Invalid index 0, size is 0 at the line signed with *.
// initial declarations:
List<String> filenameEntries = new ArrayList<String>();
List<String> idEntries = new ArrayList<String>();
/* various operations that fill
the two ArrayList here... */
// sorting:
List<String> oldFilenameEntries = new ArrayList<String>();
List<String> oldIdEntries = new ArrayList<String>();
oldFilenameEntries = filenameEntries;
oldIdEntries = idEntries;
idEntries.clear();
Collections.sort(filenameEntries);
for (int i = 0; i < filenameEntries.size(); i++ ) {
for (int j = 0; j < oldFilenameEntries.size(); j++ ) {
if (oldFilenameEntries.get(j) == filenameEntries.get(i)) {
idEntries.add(oldIdEntries.get(j)); // *
}
}
}
My idea was to search into the old ArrayList for every element from the new one, and then use this "old" index to re-polulate the other ArrayList.
(I have the restriction that the other "sorted" ArrayList must be again idEntries. This is way I did this sort of transfer)
Any suggestion?
Thanks.
EDIT:
I thought it was a sorting issue and then came out I missed the right way to make a copy for the ArrayLists. Thanks to everyone that pointed out that the error was at
oldFilenameEntries = filenameEntries;
oldIdEntries = idEntries;
and why.
I accepted the answer that pointed me more quickly to the solution.
I removed the two lines above and changed the previous into
List<String> oldFilenameEntries = new ArrayList<String>(filenameEntries);
List<String> oldIdEntries = new ArrayList<String>(idEntries);
and from what I can see ATM all seems to work as expected.
The issue is the assignment: oldIdEntries = idEntries; this is causing both references to point to same list so when you do idEntries.clear(); you have cleared the one list to which both are pointing. You need to make a copy of the list not just assign the reference.
Collections.copy
Lists.copy
ImmutableList.copy()
The problem is in these 2 lines:
oldFilenameEntries = filenameEntries;
oldIdEntries = idEntries;
After this, both old... and original variables point to the same list. Then you call idEntries.clear(). This clears both idEntries and oldIdEntries since they point to the same list.
For this to work, you need to copy the list instead of just assigning it. You could use Collections.copy(). Here is an example:
Java Collections copy list - I don't understand
On a different note, this approach seems too complex - but it's also not very clear what you are trying to accomplish so I can't suggest a better way.
Iterate over the soreted list, clone each object and then add it to the new array list
Two issues:
One:
oldFilenameEntries = filenameEntries;
oldIdEntries = idEntries;
Now, both old and new entries point to the same list.
Then, idEntries.clear().
This clears both old and new entries.
If you want to do this somehow, use Collections.copy()
Two:
If you're just going to check for equality, I don't see why you need to have two for-loops, and have both sorted.
You could just do this:
for (int i = 0; i < filenameEntries.size(); i++ ) {
if (oldFilenameEntries.contains(filenameEntries.get(i)) {
idEntries.add(oldIdEntries.get(j)); // *
}
}
}
NOTE: as I don't know what the original point of your code was, and equality checking was all I could infer from your snippet, I'm suggesting this.
For example: String[] str = {"M1","M1","M1","M2","M3"};
The most recommended is the answer - HashSet. Which methods or you have better idea?
Unless you want to implement this yourself, a Set is the way to go. A set will only allow unique elements to be added and will automatically filter duplicates.
The HashSet functionality works as follows:
The hash is computed for the object. Next the set checks if any of the objects with the same hash-value .equals() the new value. If so, the new value is ignored. If not, it is added to the set.
If you add everything to the set and then ask for its size, you will get the amount of unique elements.
new HashSet(Arrays.asList(str)).size();
I prefer to use things that are already provided natively. Which in your requirement is Set.
You can do the following -
Set<String> set = new HashSet<String>(Arrays.asList(str));
set.size();
You can try this too
String[] str = {"M1","M1","M1","M2","M3"};
HashMap<String,String> map=new HashMap<>();
for(String i:str){
map.put(i, i);
}
System.out.println(map.keySet().size());
Instead of creating a temporary list as in other answers, you can also use:
Set<String> set = new HashSet<> ();
Collections.addAll(set, str);
int countUnique = set.size();