Repository: AY2425S2-CS2103T-T15-2/tp
Pull request #38: Add multiple index deletion in delete command
Author: login: sreelakshmiharidos
Labels: name: type.Enhancement
description: An enhancement to an existing story
Created: 2025-03-13T14:44:24Z | Merged: 2025-03-13T15:16:55Z



Diff:
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 1135ac19b74..05f3cea7288 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -3,32 +3,32 @@
 import static java.util.Objects.requireNonNull;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.ToStringBuilder;
 import seedu.address.logic.Messages;
 import seedu.address.logic.commands.exceptions.CommandException;
 import seedu.address.model.Model;
 import seedu.address.model.person.Person;
 
 /**
- * Deletes a person identified using it's displayed index from the address book.
+ * Deletes multiple persons identified using displayed indices from the address book.
  */
 public class DeleteCommand extends Command {
 
     public static final String COMMAND_WORD = "delete";
 
     public static final String MESSAGE_USAGE = COMMAND_WORD
-            + ": Deletes the person identified by the index number used in the displayed person list.\n"
-            + "Parameters: INDEX (must be a positive integer)\n"
-            + "Example: " + COMMAND_WORD + " 1";
+            + ": Deletes the persons identified by the index numbers used in the displayed person list.\n"
+            + "Parameters: INDEX1 INDEX2 ... (must be positive integers, up to 10 indices)\n"
+            + "Example: " + COMMAND_WORD + " 1 3 5";
 
-    public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
+    public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Persons:\n%1$s";
 
-    private final Index targetIndex;
+    private final List<Index> targetIndices;
 
-    public DeleteCommand(Index targetIndex) {
-        this.targetIndex = targetIndex;
+    public DeleteCommand(List<Index> targetIndices) {
+        this.targetIndices = targetIndices;
     }
 
     @Override
@@ -36,13 +36,25 @@ public CommandResult execute(Model model) throws CommandException {
         requireNonNull(model);
         List<Person> lastShownList = model.getFilteredPersonList();
 
-        if (targetIndex.getZeroBased() >= lastShownList.size()) {
-            throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+        // Validate that all indices are within range
+        for (Index index : targetIndices) {
+            if (index.getZeroBased() >= lastShownList.size()) {
+                throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+            }
         }
 
-        Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
-        model.deletePerson(personToDelete);
-        return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, Messages.format(personToDelete)));
+        // Sort indices in descending order to avoid index shifting issues during deletion
+        List<Person> personsToDelete = targetIndices.stream()
+                .map(index -> lastShownList.get(index.getZeroBased()))
+                .collect(Collectors.toList());
+
+        // Perform deletions
+        personsToDelete.forEach(model::deletePerson);
+
+        return new CommandResult(String.format(
+                MESSAGE_DELETE_PERSON_SUCCESS,
+                personsToDelete.stream().map(Messages::format).collect(Collectors.joining("\n"))
+        ));
     }
 
     @Override
@@ -51,19 +63,16 @@ public boolean equals(Object other) {
             return true;
         }
 
-        // instanceof handles nulls
         if (!(other instanceof DeleteCommand)) {
             return false;
         }
 
         DeleteCommand otherDeleteCommand = (DeleteCommand) other;
-        return targetIndex.equals(otherDeleteCommand.targetIndex);
+        return targetIndices.equals(otherDeleteCommand.targetIndices);
     }
 
     @Override
     public String toString() {
-        return new ToStringBuilder(this)
-                .add("targetIndex", targetIndex)
-                .toString();
+        return "DeleteCommand{" + "targetIndices=" + targetIndices + '}';
     }
 }
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
index 3527fe76a3e..25949f46d00 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
@@ -2,6 +2,9 @@
 
 import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import seedu.address.commons.core.index.Index;
 import seedu.address.logic.commands.DeleteCommand;
 import seedu.address.logic.parser.exceptions.ParseException;
@@ -11,19 +14,33 @@
  */
 public class DeleteCommandParser implements Parser<DeleteCommand> {
 
+    private static final int MAX_DELETE_COUNT = 10;
+
     /**
      * Parses the given {@code String} of arguments in the context of the DeleteCommand
      * and returns a DeleteCommand object for execution.
      * @throws ParseException if the user input does not conform the expected format
      */
     public DeleteCommand parse(String args) throws ParseException {
-        try {
-            Index index = ParserUtil.parseIndex(args);
-            return new DeleteCommand(index);
-        } catch (ParseException pe) {
-            throw new ParseException(
-                    String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
+        String[] parts = args.trim().split("\\s+");
+        List<Index> indices = new ArrayList<>();
+
+        if (parts.length == 0 || parts[0].isEmpty()) {
+            throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
         }
-    }
 
+        if (parts.length > MAX_DELETE_COUNT) {
+            throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+        }
+
+        for (String part : parts) {
+            try {
+                indices.add(ParserUtil.parseIndex(part));
+            } catch (ParseException e) {
+                throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+            }
+        }
+
+        return new DeleteCommand(indices);
+    }
 }
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
index 643a1d08069..895f4e962a6 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -12,6 +12,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import seedu.address.commons.core.index.Index;
 import seedu.address.logic.commands.exceptions.CommandException;
@@ -125,4 +126,15 @@ public static void showPersonAtIndex(Model model, Index targetIndex) {
         assertEquals(1, model.getFilteredPersonList().size());
     }
 
+    /**
+     * Updates {@code model}'s filtered list to show only the persons at the given {@code indices}
+     * in the {@code model}'s address book.
+     */
+    public static void showPersonsAtIndices(Model model, Index... indices) {
+        List<Person> filteredPersons = Arrays.stream(indices)
+                .map(index -> model.getFilteredPersonList().get(index.getZeroBased()))
+                .collect(Collectors.toList());
+        model.updateFilteredPersonList(filteredPersons::contains);
+        assertTrue(model.getFilteredPersonList().size() >= indices.length);
+    }
 }
diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
index b6f332eabca..7a298b6c04e 100644
--- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
@@ -6,10 +6,16 @@
 import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
 import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
 import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
+import static seedu.address.logic.commands.CommandTestUtil.showPersonsAtIndices;
 import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
 import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON;
 import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
 import org.junit.jupiter.api.Test;
 
 import seedu.address.commons.core.index.Index;
@@ -28,9 +34,10 @@ public class DeleteCommandTest {
     private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
 
     @Test
-    public void execute_validIndexUnfilteredList_success() {
+    public void execute_validSingleIndexUnfilteredList_success() {
         Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
-        DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+        List<Index> indicesToDelete = List.of(INDEX_FIRST_PERSON);
+        DeleteCommand deleteCommand = new DeleteCommand(indicesToDelete);
 
         String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
                 Messages.format(personToDelete));
@@ -41,20 +48,40 @@ public void execute_validIndexUnfilteredList_success() {
         assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
     }
 
+    @Test
+    public void execute_validMultipleIndicesUnfilteredList_success() {
+        List<Index> indicesToDelete = Arrays.asList(INDEX_FIRST_PERSON, INDEX_SECOND_PERSON, INDEX_THIRD_PERSON);
+        List<Person> personsToDelete = indicesToDelete.stream()
+                .map(index -> model.getFilteredPersonList().get(index.getZeroBased()))
+                .toList();
+
+        DeleteCommand deleteCommand = new DeleteCommand(indicesToDelete);
+
+        String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
+                personsToDelete.stream().map(Messages::format).collect(Collectors.joining("\n")));
+
+        ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+        personsToDelete.forEach(expectedModel::deletePerson);
+
+        assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
+    }
+
     @Test
     public void execute_invalidIndexUnfilteredList_throwsCommandException() {
         Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
-        DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+        List<Index> indicesToDelete = List.of(outOfBoundIndex);
+        DeleteCommand deleteCommand = new DeleteCommand(indicesToDelete);
 
         assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
     }
 
     @Test
-    public void execute_validIndexFilteredList_success() {
+    public void execute_validSingleIndexFilteredList_success() {
         showPersonAtIndex(model, INDEX_FIRST_PERSON);
 
         Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
-        DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
+        List<Index> indicesToDelete = List.of(INDEX_FIRST_PERSON);
+        DeleteCommand deleteCommand = new DeleteCommand(indicesToDelete);
 
         String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
                 Messages.format(personToDelete));
@@ -66,6 +93,27 @@ public void execute_validIndexFilteredList_success() {
         assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
     }
 
+    @Test
+    public void execute_validMultipleIndicesFilteredList_success() {
+        showPersonsAtIndices(model, INDEX_FIRST_PERSON, INDEX_SECOND_PERSON);
+
+        List<Index> indicesToDelete = List.of(Index.fromZeroBased(0), Index.fromZeroBased(1)); // Pick valid indices
+        List<Person> personsToDelete = indicesToDelete.stream()
+                .map(index -> model.getFilteredPersonList().get(index.getZeroBased()))
+                .toList();
+
+        DeleteCommand deleteCommand = new DeleteCommand(indicesToDelete);
+
+        String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
+                personsToDelete.stream().map(Messages::format).collect(Collectors.joining("\n")));
+
+        Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+        personsToDelete.forEach(expectedModel::deletePerson);
+        showNoPerson(expectedModel);
+
+        assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
+    }
+
     @Test
     public void execute_invalidIndexFilteredList_throwsCommandException() {
         showPersonAtIndex(model, INDEX_FIRST_PERSON);
@@ -74,21 +122,25 @@ public void execute_invalidIndexFilteredList_throwsCommandException() {
         // ensures that outOfBoundIndex is still in bounds of address book list
         assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
 
-        DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
+        List<Index> indicesToDelete = List.of(outOfBoundIndex);
+        DeleteCommand deleteCommand = new DeleteCommand(indicesToDelete);
 
         assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
     }
 
     @Test
     public void equals() {
-        DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_PERSON);
-        DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_PERSON);
+        List<Index> firstList = List.of(INDEX_FIRST_PERSON);
+        List<Index> secondList = List.of(INDEX_SECOND_PERSON);
+
+        DeleteCommand deleteFirstCommand = new DeleteCommand(firstList);
+        DeleteCommand deleteSecondCommand = new DeleteCommand(secondList);
 
         // same object -> returns true
         assertTrue(deleteFirstCommand.equals(deleteFirstCommand));
 
         // same values -> returns true
-        DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_PERSON);
+        DeleteCommand deleteFirstCommandCopy = new DeleteCommand(firstList);
         assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy));
 
         // different types -> returns false
@@ -103,9 +155,9 @@ public void equals() {
 
     @Test
     public void toStringMethod() {
-        Index targetIndex = Index.fromOneBased(1);
-        DeleteCommand deleteCommand = new DeleteCommand(targetIndex);
-        String expected = DeleteCommand.class.getCanonicalName() + "{targetIndex=" + targetIndex + "}";
+        List<Index> targetIndices = List.of(Index.fromOneBased(1), Index.fromOneBased(2));
+        DeleteCommand deleteCommand = new DeleteCommand(targetIndices);
+        String expected = "DeleteCommand{targetIndices=" + targetIndices + "}";
         assertEquals(expected, deleteCommand.toString());
     }
 
diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
index 5a1ab3dbc0c..099bfb49d3b 100644
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
@@ -13,6 +13,7 @@
 
 import org.junit.jupiter.api.Test;
 
+import seedu.address.commons.core.index.Index;
 import seedu.address.logic.commands.AddCommand;
 import seedu.address.logic.commands.ClearCommand;
 import seedu.address.logic.commands.DeleteCommand;
@@ -48,9 +49,13 @@ public void parseCommand_clear() throws Exception {
 
     @Test
     public void parseCommand_delete() throws Exception {
-        DeleteCommand command = (DeleteCommand) parser.parseCommand(
+        List<Index> indices = List.of(INDEX_FIRST_PERSON);
+        DeleteCommand expectedCommand = new DeleteCommand(indices);
+
+        DeleteCommand actualCommand = (DeleteCommand) parser.parseCommand(
                 DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
-        assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
+
+        assertEquals(expectedCommand, actualCommand);
     }
 
     @Test
diff --git a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
index 6a40e14a649..74aceb4f997 100644
--- a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
@@ -4,29 +4,40 @@
 import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
 import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
 import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON;
+
+import java.util.List;
 
 import org.junit.jupiter.api.Test;
 
+import seedu.address.commons.core.index.Index;
 import seedu.address.logic.commands.DeleteCommand;
 
-/**
- * As we are only doing white-box testing, our test cases do not cover path variations
- * outside of the DeleteCommand code. For example, inputs "1" and "1 abc" take the
- * same path through the DeleteCommand, and therefore we test only one of them.
- * The path variation for those two cases occur inside the ParserUtil, and
- * therefore should be covered by the ParserUtilTest.
- */
 public class DeleteCommandParserTest {
 
     private DeleteCommandParser parser = new DeleteCommandParser();
 
     @Test
-    public void parse_validArgs_returnsDeleteCommand() {
-        assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_PERSON));
+    public void parse_validSingleIndex_returnsDeleteCommand() {
+        List<Index> indices = List.of(INDEX_FIRST_PERSON);
+        assertParseSuccess(parser, "1", new DeleteCommand(indices));
+    }
+
+    @Test
+    public void parse_validMultipleIndices_returnsDeleteCommand() {
+        List<Index> indices = List.of(INDEX_FIRST_PERSON, INDEX_SECOND_PERSON, INDEX_THIRD_PERSON);
+        assertParseSuccess(parser, "1 2 3", new DeleteCommand(indices));
     }
 
     @Test
     public void parse_invalidArgs_throwsParseException() {
         assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
     }
+
+    @Test
+    public void parse_exceedMaxLimit_throwsParseException() {
+        assertParseFailure(parser, "1 2 3 4 5 6 7 8 9 10 11",
+                String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+    }
 }


Reviews:
user: login: ypuppy
body: looks all good. that's a very good enhancement !! 
state: APPROVED
author_association: NONE
submitted_at: 2025-03-13T15:15:31Z
user: login: heyitssakinah
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-13T15:20:08Z
user: login: heyitssakinah
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-13T15:26:14Z
user: login: heyitssakinah
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-13T15:28:13Z

Review comments:
diff_hunk: @@ -11,19 +14,33 @@
  */
 public class DeleteCommandParser implements Parser<DeleteCommand> {
 
+    private static final int MAX_DELETE_COUNT = 10;
+
     /**
      * Parses the given {@code String} of arguments in the context of the DeleteCommand
      * and returns a DeleteCommand object for execution.
      * @throws ParseException if the user input does not conform the expected format
      */
     public DeleteCommand parse(String args) throws ParseException {
-        try {
-            Index index = ParserUtil.parseIndex(args);
-            return new DeleteCommand(index);
-        } catch (ParseException pe) {
-            throw new ParseException(
-                    String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
+        String[] parts = args.trim().split("\\s+");
path: src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
user: login: heyitssakinah
body: this section can be transferred into ParserUtil and keep just one try catch here for the parts.
created_at: 2025-03-13T15:20:08Z
author_association: NONE
diff_hunk: @@ -41,20 +48,40 @@ public void execute_validIndexUnfilteredList_success() {
         assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
     }
 
+    @Test
path: src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
user: login: heyitssakinah
body: Add a test for deletion with unordered indexes ie. delete 6, 3, 1
created_at: 2025-03-13T15:26:13Z
author_association: NONE
diff_hunk: @@ -3,46 +3,58 @@
 import static java.util.Objects.requireNonNull;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.ToStringBuilder;
 import seedu.address.logic.Messages;
 import seedu.address.logic.commands.exceptions.CommandException;
 import seedu.address.model.Model;
 import seedu.address.model.person.Person;
 
 /**
- * Deletes a person identified using it's displayed index from the address book.
+ * Deletes multiple persons identified using displayed indices from the address book.
  */
 public class DeleteCommand extends Command {
 
     public static final String COMMAND_WORD = "delete";
 
     public static final String MESSAGE_USAGE = COMMAND_WORD
-            + ": Deletes the person identified by the index number used in the displayed person list.\n"
-            + "Parameters: INDEX (must be a positive integer)\n"
-            + "Example: " + COMMAND_WORD + " 1";
+            + ": Deletes the persons identified by the index numbers used in the displayed person list.\n"
+            + "Parameters: INDEX1 INDEX2 ... (must be positive integers, up to 10 indices)\n"
+            + "Example: " + COMMAND_WORD + " 1 3 5";
 
-    public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
+    public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Persons:\n%1$s";
 
-    private final Index targetIndex;
+    private final List<Index> targetIndices;
 
-    public DeleteCommand(Index targetIndex) {
-        this.targetIndex = targetIndex;
+    public DeleteCommand(List<Index> targetIndices) {
+        this.targetIndices = targetIndices;
     }
 
     @Override
     public CommandResult execute(Model model) throws CommandException {
         requireNonNull(model);
         List<Person> lastShownList = model.getFilteredPersonList();
 
-        if (targetIndex.getZeroBased() >= lastShownList.size()) {
-            throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+        // Validate that all indices are within range
+        for (Index index : targetIndices) {
+            if (index.getZeroBased() >= lastShownList.size()) {
+                throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+            }
         }
 
-        Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
-        model.deletePerson(personToDelete);
-        return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, Messages.format(personToDelete)));
+        // Sort indices in descending order to avoid index shifting issues during deletion
path: src/main/java/seedu/address/logic/commands/DeleteCommand.java
user: login: heyitssakinah
body: how does this ensure deletion by descending order
created_at: 2025-03-13T15:28:12Z
author_association: NONE

PR comments:
user: login: codecov[bot]
created_at: 2025-03-13T15:03:15Z
body: ## [Codecov](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2) Report
Attention: Patch coverage is `92.00000%` with `2 lines` in your changes missing coverage. Please review.

| [Files with missing lines](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2) | Patch % | Lines |
|---|---|---|
| [...eedu/address/logic/parser/DeleteCommandParser.java](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fseedu%2Faddress%2Flogic%2Fparser%2FDeleteCommandParser.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2#diff-c3JjL21haW4vamF2YS9zZWVkdS9hZGRyZXNzL2xvZ2ljL3BhcnNlci9EZWxldGVDb21tYW5kUGFyc2VyLmphdmE=) | 83.33% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2) |

| [Files with missing lines](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2) | Coverage Δ | Complexity Δ | |
|---|---|---|---|
| [...va/seedu/address/logic/commands/DeleteCommand.java](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fseedu%2Faddress%2Flogic%2Fcommands%2FDeleteCommand.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2#diff-c3JjL21haW4vamF2YS9zZWVkdS9hZGRyZXNzL2xvZ2ljL2NvbW1hbmRzL0RlbGV0ZUNvbW1hbmQuamF2YQ==) | `100.00% <100.00%> (ø)` | `9.00 <3.00> (+2.00)` | |
| [...eedu/address/logic/parser/DeleteCommandParser.java](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fseedu%2Faddress%2Flogic%2Fparser%2FDeleteCommandParser.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2#diff-c3JjL21haW4vamF2YS9zZWVkdS9hZGRyZXNzL2xvZ2ljL3BhcnNlci9EZWxldGVDb21tYW5kUGFyc2VyLmphdmE=) | `84.61% <83.33%> (-15.39%)` | `4.00 <3.00> (+2.00)` | :arrow_down: |

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: codecov[bot]
created_at: 2025-03-13T15:03:15Z
body: ## [Codecov](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2) Report
Attention: Patch coverage is `92.00000%` with `2 lines` in your changes missing coverage. Please review.

| [Files with missing lines](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2) | Patch % | Lines |
|---|---|---|
| [...eedu/address/logic/parser/DeleteCommandParser.java](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fseedu%2Faddress%2Flogic%2Fparser%2FDeleteCommandParser.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2#diff-c3JjL21haW4vamF2YS9zZWVkdS9hZGRyZXNzL2xvZ2ljL3BhcnNlci9EZWxldGVDb21tYW5kUGFyc2VyLmphdmE=) | 83.33% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2) |

| [Files with missing lines](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2) | Coverage Δ | Complexity Δ | |
|---|---|---|---|
| [...va/seedu/address/logic/commands/DeleteCommand.java](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fseedu%2Faddress%2Flogic%2Fcommands%2FDeleteCommand.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2#diff-c3JjL21haW4vamF2YS9zZWVkdS9hZGRyZXNzL2xvZ2ljL2NvbW1hbmRzL0RlbGV0ZUNvbW1hbmQuamF2YQ==) | `100.00% <100.00%> (ø)` | `9.00 <3.00> (+2.00)` | |
| [...eedu/address/logic/parser/DeleteCommandParser.java](https://app.codecov.io/gh/AY2425S2-CS2103T-T15-2/tp/pull/38?src=pr&el=tree&filepath=src%2Fmain%2Fjava%2Fseedu%2Faddress%2Flogic%2Fparser%2FDeleteCommandParser.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=AY2425S2-CS2103T-T15-2#diff-c3JjL21haW4vamF2YS9zZWVkdS9hZGRyZXNzL2xvZ2ljL3BhcnNlci9EZWxldGVDb21tYW5kUGFyc2VyLmphdmE=) | `84.61% <83.33%> (-15.39%)` | `4.00 <3.00> (+2.00)` | :arrow_down: |

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE