I have two lists in Kotlin, of the same size, foodObjects: MutableList<ParseObject>? and checked: MutableList<Boolean>?. I need to do a for loop and get the objectId from foodObjects every time that an element of checked is true. So it is this in Java:
for (int i = 0; i < foodObjects.size(); i++) {
// here
}
But in Kotlin, I don't know why, there are some problems. In fact, if I do this:
for (i in 0..foodObjects!!.size) {
if (checked?.get(i) == true) {
objectsId?.add(foodObjects.get(i).objectId)
}
}
I've got IndexOutOfBoundsException. I don't know why, it continues the loop also at foodObjects.size. I could do it also with filter and map:
(0..foodObjects!!.size)
.filter { checked?.get(it) == true }
.forEach { objectsId?.add(foodObjects.get(it).objectId) }
but I'm getting the same error. I use this to stop the error and get it to work:
for (i in 0..foodObjects!!.size) {
if (i < foodObjects.size) {
if (checked?.get(i) == true) {
objectsId?.add(foodObjects.get(i).objectId)
}
}
}
Everyone could tell me why in Kotlin I need to do it, when in Java it works good?
Ranges in Kotlin are inclusive, therefore 0..foodObjects!!.size starts at 0 and ends at foodObjects.size, including both ends. This causes the exception when your loop attempts to index the list with its own size, which is one more than the largest valid index.
To create a range that doesn't include the upper bound (like your Java loop), you can use until:
for(i in 0 until foodObjects!!.size) {
// ...
}
You could also clean your code up a bit if you did null checks on the collections you're using up front:
if (foodObjects != null && checked != null && objectsId != null) {
for (i in 0 until foodObjects.size) {
if (checked.get(i) == true) {
objectsId.add(foodObjects.get(i).objectId)
}
}
}
else {
// handle the case when one of the lists is null
}
And to get rid of having to handle indexes altogether, you can use the indices property of a list (plus I use the indexing operator here instead of get calls):
for (i in foodObjects.indices) {
if (checked[i]) {
objectsId.add(foodObjects[i].objectId)
}
}
You could also use forEachIndexed:
foodObjects.forEachIndexed { i, foodObject ->
if (checked[i]) {
objectsId.add(foodObject.objectId)
}
}
Take a look at this example from the Kotlin documentation for ranges:
if (i in 1..10) { // equivalent of 1 <= i && i <= 10
println(i)
}
As you can see
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
will be printed. So, the 10 is included.
The highest index of your collection foodObjects is (foodObjects.size() - 1) because it starts with 0.
So, to fix your problem, just do this:
for(i in 0..(foodObjects.size - 1)) {
// ...
}
A better way to write this would be:
for((i, element) in foodObjects.withIndex()){
// do something with element
println("The index is $i")
}
This way you have the element and the index at once and don't need to worry about ranges.
*I removed the null checks for simplicity.
Here are various ways to ensure the index is valid:
if (index in myList.indices) {
// index is valid
}
// The rangeUntil operator (..<) is still exprimental in Kotlin 1.7.20
if (index in 0..<myList.size) {
// index is valid
}
if (index in 0 until myList.size) {
// index is valid
}
if (index in 0..myList.lastIndex) {
// index is valid
}
if (index >= 0 && index <= myList.lastIndex) {
// index is valid
}
// Note: elements of the list should be non-null
if (myList.getOrNull(index) != null) {
// index is valid
}
// Note: elements of the list should be non-null
myList.getOrNull(index)?.let { element ->
// index is valid; use the element
}
Related
I'm trying to prevent conditionals jumps from being useless for example by deleting that :
if(1 > 10) {
return;
}
So I decided to create a BasicInterpreter to check if the frame of the jump is null and if so remove it. And it's not null so it doesn't detect it as useless.
Code which doesn't work :
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
if(frames[i] == null) {
System.out.println("This jump is useless");
}
}
}
}
Then I tried to get some values of stack to manually calculate but without any success (I found that but I cannot port the code to use it on jumps ASM Get exact value from stack frame):
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
// getStackSize() returns 2 so -> 0 and 1
frames[i].getStack(0); // this is probably 1
frames[i].getStack(1); // this is probably 10
// but it returns a BasicValue so I can't check if the code works or not (we cannot get values)
}
}
}
And the last thing I tried was to get the size of the instructions which are used by the jump to delete them (of course it doesn't detect if it's a useless code but I can at least delete it).
In fact I tried to create a method which returns a constant int so I can detect if getValue is called in the instructions of the jump (if I detect the invoke, I delete the instructions of the jump and the jump itself of course):
Example:
if(1 > getValue()) { //getValue() returns 10
return;
}
Code:
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
ArrayList<AbstractInsnNode> nodesR = new ArrayList<>();
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
ArrayList<AbstractInsnNode> toRemove = new ArrayList<>();
for (int ia = 1; ia < frames[i].getMaxStackSize() + 2; ia++) { // I started from 1 and added 2 to getMaxStackSize because I wasn't getting all the instructions
toRemove.add(mn.instructions.get(i - ia));
}
toRemove.add(mn.instructions.get(i)); // I add the jump to the list
for (AbstractInsnNode aaa : toRemove) {
if (aaa.getOpcode() == INVOKESTATIC) { // the invokestatic is getValue
for (AbstractInsnNode aaas : toRemove) {
nodesR.add(aaas);
}
break;
}
}
}
}
}
for (AbstractInsnNode aaas : nodesR) {
mn.instructions.remove(aaas);
}
} catch (AnalyzerException e) {
e.printStackTrace();
}
This code is probably horrible and not optimized but I tried a LOT of things without any success. The getMaxStackSize() doesn't return a number which is 100% correct (sometimes it doesn't take additions etc so it deletes instructions such as labels etc...).
What I'm trying to do:
Parsing through a method and check if a conditional jump will always be false (so the code inside will never gets executed) then remove it.
I tried two different way:
Use a BasicInterpreter to check if this jump will get executed with constant values then try it to see if it will always be false
Check if the jump contains a certain method (for example getValue() which returns 10 and compare if it's less than 1) then remove it
What I don't understand :
I think that there is frames in each instructions and that it contains the local variables table and the values that the frame is using – StackMap ? - ( for example if the instruction compare if an int is less than another it would return [II] right ?
I don't know if I can use a BasicInterpreter to test if the two constant ints always return the same result
StackMap = the Stack ? or it's different like the StackMap is a part of the stack which contains the needed values for the instruction ?
I have a method which writes the elements of the array list to a file. The problem is i need a new line for the next 6 consecutive elements in the List.
So the file will look like this.
wrds,wrds,wrds,wrds,wrds,wrds
wrds,wrds,wrds,wrds,wrds,wrds
etc. so the list will look like this:
wrds,wrds,wrds,wrds,wrds,wrds,wrds,wrds,wrds,wrds,wrds,wrds
I need to split the elements by 6 and write them on a new line each time. How do i do this?
public void printToFile()
{
for (int i = 0; i <= one.size(); i++) {
try {
output.write((String)one.get(i));
if (i == 6) {
output.newLine();
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
Everything you need here is an if statement that will evaluate to true for 6th, 12th, 18th... etc. element. You can achieve this using modulo operator (%). i % 6 == 0 will evaluate to true for any ithat is a multiple of 6.
String[] m_cPackageName;
int m_size;
int j=0;
List<ApplicationInfo> installedList = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
m_size = installedList.size();
m_cPackageName=new String[m_size];
for (PackageInfo pi : pkginfoList) {
try {
m_appinfo = packageManager.getApplicationInfo(pi.packageName, 0);
if ((m_appinfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
// equal to zoo means system apps, not equal is third party installed apps
m_cPackageName[j]=pi.packageName;
j++;
}
} catch (NameNotFoundException e) {
Log.d(getClass().getSimpleName(), "Name not found", e);
}
Here I'm getting total size of installedList is 56..After filling the value in array it display in null values. how can i eliminate the null values.. Any one Help for me..
OUTPUT :
m_cPackageName=String[56];
m_cPackageName[0]="Myvalue"
m_cPackageName[1]="null"
m_cPackageName[2]="null"
.
.
.
m_cPackageName[55]="null"
Less than m_size elements are being added to the array (of size m_size), which results in unassigned null elements at the end.
This is because j is only increased sometimes - inside a conditional ((m_appinfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0), and only when an exception is not thrown and caught.
A simple solution is to use an ArrayList, then only add the "approved" elements. Because a List/ArrayList grows on demand, there are no trailing null (unassigned) elements as might be found in a fixed-size array.
// List, not array
List<String> m_cPackageName = new ArrayList<String>();
// ..
if ((m_appinfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
// Only added to list sometimes, but m_cPackageName.size() is
// always the count of elements that HAVE been added.
m_cPackageName.add(pi.packageName);
}
// Then, if you really need an array, which will now be the proper size
// and not contain null elements because the size is computed based on the
// accepted elements in m_cPackageName which is m_cPackageName.size() ..
String[] arrayOfPackageNames = m_cPackageName.toArray(new String[0]);
add null check before inserting element to array.
if ((m_appinfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if(pi.packageName!=null){
m_cPackageName[j]=pi.packageName;
j++;
}
}
if (((m_appinfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)&& (pi.packageName != null &&!pi.packageName.equals("")) {
// equal to zoo means system apps, not equal is third party installed apps
m_cPackageName[j]=pi.packageName;
j++;
}
You are allocating the array based on the size of installedList, but you are iterating over pkginfoList. A better way to do this is to create a List<String> packageNames = new ArrayList<String>();, and then add to that list in your loop.
That way, you don't have worry about counting or size.
if ((m_appinfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
// equal to zoo means system apps, not equal is third party installed apps
if(pi.packageName!=null){
m_cPackageName[j]=pi.packageName;
j++;
}
}
If you don't need to disambiguate empty and null strings, consider storing nulls as empty; something like this:
m_cPackageName[j]=pi.packageName == null ? "" : pi.packageName;
This might reduce the risk of things blowing up as NullPointerException-s further down.
I keep seeing null pointer exceptions in my search method for the skip list I'm implementing.
public V find(K key, SkiplistMapNode<K,V> header, int level){
SkiplistMapNode<K,V> N = header;
for (int i = level-1; i >= 0; i--){
if ((N != null) && (N.getNext()[i] != null)){
while (N.getNext()[i].getKey().compareTo(key) < 0){
N = N.getNext()[i];
}
}
}
N = N.getNext()[0];
if ((N != null) && (N.getKey().compareTo(key) == 0)) return N.getValue();
else return null;
}
The line with the exception is:
while (N.getNext()[i].getKey().compareTo(key) < 0)
I pretty much copied this from this page though, so I'm not sure what would be wrong with it.
Supposing that N.getNext() advances to the next node, you need to memorize its value without advancing if you access the value more than once.
Same with iterator:
while (iterator.hasNext()) {
if (iterator.next()!=null) {
iterator.next().toString() // advances to the next item, which may be null
}
}
Fixed:
while (iterator.hasNext()) {
Object next=iterator.next(); // advance once
if (next!=null) { // check value
next.toString() // use same value, without advancing
}
}
It's hard to tell from your code where you really want to advance to the next element, and where you need the elements values again. Store the next value in a variable, and check and use this value afterwards, same as in the Iterator example above.
If you access an objects method, you should really make sure that the object isn't null. In your case, in...
while (N.getNext()[i].getKey().compareTo(key) < 0)
These...
N.getNext() //the only really important one you seem not to be checking
N.getNext()[i]
could be null and should be checked and possibly even (though less likely and debatably)
N
N.getNext()[i].getKey()
key
I have code that reads a text file and creates an input array[] of boolean type. Its size is about 100,000-300,000 items. Now the problem I'm facing is to create all those subsets of size N, 3>=N>=9, that have contiguous true values.
E.g. for N=3, [true][true][true] is the required subset if all the 3 trues are in the continuous indexes.
Although I have an algorithm created, it's very slow. I need a better solution, which is fast and efficient.
Please suggest some ideas.
public static void createConsecutivePassingDays()
{
for (String siteName : sitesToBeTestedList.keySet())
{
System.out.println("\n*****************Processing for Site--->"+siteName+" ***********************");
LinkedHashMap<String,ArrayList<String>> cellsWithPassedTripletsDates=new LinkedHashMap<String, ArrayList<String>>();
for (String cellName : sitesToBeTestedList.get(siteName))
{
System.out.println("\n*****************Processing for Cell--->"+cellName+" ***********************");
boolean failed=false;
ArrayList<String> passedDatesTriplets=new ArrayList<String>();
int consecutiveDays=0;
String tripletDate="";
String prevDate_day="";
String today_Date="";
for (String date : cellDateKpiMetOrNotMap.get(cellName).keySet())
{
System.out.println("\nprocessing for Date-->"+date);
if(!(prevDate_day.trim().equals("")))
today_Date=getNextDay(prevDate_day.substring(0, prevDate_day.lastIndexOf('_')));
if(Connection.props.getProperty("INCLUDE_WEEKENDS").equalsIgnoreCase("FALSE"))
{
if(date.endsWith("SAT") || date.endsWith("SUN") || (!(date.substring(0, date.lastIndexOf('_')).equalsIgnoreCase(today_Date))))
{
if(consecutiveDays >= Reader.days)
{
passedDatesTriplets.add(tripletDate);
}
tripletDate="";
consecutiveDays=0;
prevDate_day=date;
continue;
}
}
if(cellDateKpiMetOrNotMap.get(cellName).get(date).equalsIgnoreCase("TRUE"))
{
if(tripletDate.equals(""))
tripletDate=date;
else
tripletDate+="#"+date;
consecutiveDays++;
}
else
{
failed=true;
if(consecutiveDays >= Reader.days)//kd
{
System.out.println("Triplet to be added-->"+tripletDate);
passedDatesTriplets.add(tripletDate);
}
tripletDate="";
consecutiveDays=0;
}
prevDate_day=date;
}
if(!failed)
passedDatesTriplets.add(tripletDate);
else
{
if(tripletDate.trim().split("#").length >= Reader.days)
{
passedDatesTriplets.add(tripletDate);
}
}
cellsWithPassedTripletsDates.put(cellName, passedDatesTriplets);
}
siteItsCellsWithPassedDates.put(siteName, cellsWithPassedTripletsDates);
}
System.out.println("\n************************************************SITES***************************************");
for (String site : siteItsCellsWithPassedDates.keySet())
{
System.out.println("\n********************Site="+site+" ***********************");
for (String cellName : siteItsCellsWithPassedDates.get(site).keySet())
{
System.out.println("\nCellName="+cellName);
System.out.println(siteItsCellsWithPassedDates.get(site).get(cellName));
}
System.out.println("***********************************************************");
}
System.out.println("********************************************************************************************");
}
First I would stay away from the array[boolean] a BitSet is more memory efficient in I'd expect it to be faster as well in your case. Since it will utilize the caches better. See boolean[] vs. BitSet: Which is more efficient?
For the algorithm:
Iterate through the datastructure.
When you come across the first true, remember its position (start) until you reach a false. This is the position end
At that point you have the start and end of a contiuous interval of true values, which is basically your result. You get your subsets as starting from start to end - n.
Repeat until the end of you datastructure
You can even parallize this by starting n-processes, each handling a different part of the array, starting with the first false value after the start of the segement and continuing over the end of the segement until the first false.
The simplest algo would be to check the N values starting at index x. if there is at least one false, then you can go directly to the index x+N. otherwise you can check index x+1;
if there is no valid sequence, then you will check size/N cells.
in pseudo-code :
int max = array.length - N;
int index = 0;
boolean valid = true;
while (index < max) {
valid = true;
for (check = index; check<index+N; check++){
valid = valid && array[check];
}
if (valid) {
// you got a continous sequence of true of size N
;
index++;
} else {
index = index + N;
}
}
also, with a BitSet instead of an array you could use the nextClearByte to get the index of the next false. the difference with the previous false minus N indicate the nomber of sequences of N true (with the previous false initially valued at -1).
I will sugggest you to create a stringbuilder and append 1 for every "true" value added to the boolean array and a 0 for every "false" added. Thus your stringbuilder will have a sequence of 1s and 0s. Then just use indexOf("111") to get the starting index of the three contiguous "true" values, it will be the starting index in the stringbuilder and in your boolean array as well.