How to remove an item by index in a list?

My teacher has taught me the drop+take+append method, but I want to use List.filter. Sadly, my codes just kept getting wrong. I have done some research, it seems like I can only delete item by index if I change List to Buffer. Are there any other options? Need some guidance here, thanks!

import Text "mo:base/Text";
import List "mo:base/List";
import Nat "mo:base/Nat";
import Debug "mo:base/Debug";

actor DKeeper{
  public type Note ={
    title: Text;
    content: Text;
  };

  var notes: List.List<Note> = List.nil<Note>();

  public func createNote(titleText : Text, contentText : Text){
    let newNote : Note = {title = titleText; content = contentText};
    notes := List.push(newNote, notes);
    Debug.print(debug_show(notes));
  };

  public query func readNotes(): async[Note]{
    return List.toArray(notes);
  };

  public func deleteNote(index : Nat) {
    notes := List.filter(notes, (func (_ : Note, i : Nat) : Bool { i != index }));
  };

};

So in Motoko, a list is a linked list in the form of type List<T> = ?(T, List<T>), where its really just a tuple of the current item and the following list
See here for docs: List | Internet Computer

I would say the way you are doing it with a list is fine, but linked lists arent the best for index based operations. In a different language i would say use the array, but that also gets complicated due to immutability and whatnot, so you cant alter an array, except to replace it, or you have to use a mutable array [var ?Note], but that would just leave a null in the index location

Your best bet is to just use a Buffer, they are used like you would an array/list in a different language. They are not a ‘stable’ structure, but as long as the lists aren’t huge, then you should be fine. Just switch between a Buffer and an array

Alternatively you could use a Trie (Trie | Internet Computer) where you could store the note id as the key and add and remove notes, without an ‘index’ issue

1 Like

Thanks for your help. I have tried to write codes by using Buffer. It’s so easy to alter the codes from using List to Buffer and it has specific code(" .remove") to delete item by index. TrieSet is also nice, but it’s a bit luxurious for this project. Array turns out to be quite like List, not straightforward, needs to use “Array.slice()” and “Array.concat()”.

I’m a tyro in programming and still confused about the choice of mutable and immutable structure or which is faster to process or takes less space and whatsoever. Anyway, I choose Buffer in the end.

For anyone interested, the codes using Buffer are as follows:

import Text "mo:base/Text";
import Buffer "mo:base/Buffer";
import Nat "mo:base/Nat";
import Debug "mo:base/Debug";

actor DKeeper{
  public type Note ={
    title: Text;
    content: Text;
  };

  var notes: Buffer.Buffer<Note> = Buffer.Buffer<Note>(0);

  public func createNote(titleText : Text, contentText : Text){
    let newNote : Note = {title = titleText; content = contentText};
    notes.add(newNote);
  };

  public query func readNotes(): async[Note]{
    return Buffer.toArray(notes);
  };

  public func deleteNote(index : Nat){
    let removedNote = notes.remove(index);
 }; 

};