2

I am not a programmer. I work at warehouse and I would like to make my work easier. One of my responsibilities is to divide excel file with over 2000 rows into smaller ones and send them out. I do it manually and I would like to create a program that does it for me.

I have managed to read the data from excel. Each row is put into an Item data structure. And all of them are put into ArrayList.

public class Item{
    String ean;
    int amount;
}

Here is my problem.

I have one ArrayList with over 2000 elements. Each element has String Name and int amount.

I must divide it into smaller ArrayLists but the condition is that the total amount of item.getAmount() can´t be more than 800;

int totalAmount = 0;
int counter = 1;
List<Item> temp = new ArrayList<>();

for (Itema item: items) {  
    totalAmount += item.getAmount();
    if (totalAmount <= 800) {
        temp.add(item);
    }
    if (counter == items.size()) {
        createFile(temp);
        temp.clear();
    }
    if (totalAmount > 800) {
       createFile(temp);
       temp.clear();
       temp.add(item);
       totalAmount = 0;
   }
   counter++;
}

When I run this with ArrayList that contains thirty items each with amount 100. It creates 4 excel files. First three only have 1 row each and fourth one has 4 rows.

I can't figure it out. Any suggestions??

  • 1
    Shouldn't you be clearing `temp` *after* you've used it in `createFile`? You're erasing the list, adding an element to it, then using the erased list to create a file. – Carcigenicate Aug 31 '18 at 21:33
  • The dupe closure isn't me saying your question is bad, it's me saying that your answer is in another castle. I can't think of a better approach anyway than what's in that other answer. – Makoto Aug 31 '18 at 21:37
  • @Makoto It's not the same question. Most of those answers are irrelevant here. – shmosel Aug 31 '18 at 21:38
  • @shmosel: I ***emphatically*** disagree. If the issue is to partition their list of 2,000 records into N lists with up to 800 records, then the answers in that question *completely* cover the circumstance. Maybe you're reading something I'm not here? – Makoto Aug 31 '18 at 21:39
  • @Makoto But that's not the requirement. Read it again carefully. – shmosel Aug 31 '18 at 21:40
  • @shmosel: I am beyond the point of you trying to mansplain a requirement to me. Tell me what you've seen so I can at least get some peace in knowing why you reversed what I believe to be an applicable dupe closure. – Makoto Aug 31 '18 at 21:41
  • 2
    @Makoto, the requirement appears to be that the sum of the values of the `amount` properties of the `Item`s in each sublist not exceed 800. It's not about the sizes of the sublists. – John Bollinger Aug 31 '18 at 21:45
  • 1
    Should `totalAmount = 0;` be `totalAmount = item.getAmount();`? – Andy Turner Aug 31 '18 at 21:47
  • Now it creates 4 files. First with 8 rows, second with 9, third with 9 and fourth with 4. I need it to be has to be 8, 8, 8, 6. – MichaelColtaine Coltaine Aug 31 '18 at 21:47
  • Because you're only checking after it overflows. You need to check and flush first. – shmosel Aug 31 '18 at 21:49
  • Thank you for quick reactions. What do you mean by check and flush? – MichaelColtaine Coltaine Aug 31 '18 at 21:52
  • Check if it's going to overflow, write to file if necessary, and only then add the item. – shmosel Aug 31 '18 at 22:02
  • That makes more sense then @JohnBollinger. I withdraw my objection. – Makoto Aug 31 '18 at 22:11

2 Answers2

3

I find it easier not to think of it in terms of adding things into a list, and then clearing it afterwards, but rather just by identifying the start and end of sublists which don't exceed the target sum (*):

int start = 0;
while (start < items.size()) {
  // Move the end pointer until your total exceeds 800.
  int end = start + 1;
  int totalAmount = items.get(start).getAmount();
  while (end < items.size()) {
    int amount = items.get(end).getAmount();
    if (totalAmount + amount > 800) {
      break;
    }
    totalAmount += amount;
    end++;
  }

  // Now flush the sublist between start and end:
  createFile(items.subList(start, end));

  // Now move on to the next.
  start = end;
}

(*) You may get a single-element sublist which exceeds the sum, e.g. if the amount is 801. You can't do anything with that case, other than write it by itself.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • This one works, I am very thankful to you and everyone else who answered in this thread. It is going to make my work much less annoying. If I may ask one more question. What if I want each file to have maximum of 8 rows? – MichaelColtaine Coltaine Aug 31 '18 at 22:35
  • Change the condition on the while loop to `end < items.size() && (end - start) < 8`. – Andy Turner Aug 31 '18 at 22:50
1

With respect to the revised code producing sublists of length 8, 9, 9, 4, the problem is that after flushing the current sublist to a file, you reset the totalAmount incorrectly, not taking into account the item you are currently processing. You end up with temp containing one element, but totalAmount being zero.

To make totalAmount reflect the correct sum of the amounts of the items in temp, that alternative should look more like this:

    if (totalAmount > 800) {
        createFile(temp);
        temp.clear();
        temp.add(item);                  // temp now contains one element
        totalAmount = item.getAmount();  // this is the 'amount' of that element
    }
John Bollinger
  • 160,171
  • 8
  • 81
  • 157