0

What is the best way for me to remove an element from List<> A that is not in List<> B. On Top of this before I remove the Element I need to run a function on that Element (Callback is run when value changed).

For Example

List<Chunk> ActiveChunks = //List Of Active Chunks.
void UpdateChunks()
{
   List<Chunk> chunks = //Chunks To Activate
   if (ActiveChunks[Element] is not Contained In chunks){
      A.Active = False
      A.Remove[Element]
   }
   //After Removing Chunks That do not exist in "chunks" add from chunks to ActiveChunks What is not In already in Chunks
} 

What My Code Looks Like

private List<Chunk> ActiveChunks = new List<Chunk>();
private void OnPlayerMoved(Character c)
{
    //Current chunk That Player is in
    List<Chunk> chunks = new List<Chunk>();
    for (int i = -(GameManager.ViewRange - 1); i < GameManager.ViewRange - 1; i++)
    {
        Chunk chunk = world.ChunkAtWorldPos(c.PosX + i, c.PosY + i);
        if (chunk != null)
            chunks.Add(chunk);
    }
    if (ActiveChunks.Count > 0)
    {
        foreach (Chunk chunk in ActiveChunks)
        {
            if (chunks.Contains(chunk) == false)
            {
                chunk.Active = false;
            }
        }
        //This Line From Answer down Below
        ActiveChunks.RemoveAll(x => x.Active == false);
        foreach (Chunk chunk in chunks)
        {
            if (ActiveChunks.Contains(chunk) == false)
            {
                chunk.Active = true;
                ActiveChunks.Add(chunk);
            }
        }
    }
    else
        ActiveChunks.AddRange(chunks);
}

public class Chunk
    {
        //Position
        public readonly int X;
        public readonly int Y;

        public Tile[,] Tiles;

        private bool active = false;
        public bool Active{
            get{return active;}
            set{
                if (value == true && value != active)
                    cbOnActivate?.Invoke(this);
                else if (value != active)
                    cbOnDeactivate?.Invoke(this);

                active = value;
            }
        }

        Action<Chunk> cbOnActivate;
        Action<Chunk> cbOnDeactivate;

        //Constructor
        public Chunk(int X, int Y)
        {
            this.X = X;
            this.Y = Y;
        }

        void RegisterOnActivateCallback(Action<Chunk> callback){
            cbOnActivate += callback;
        }
        void RegisterOnDeactivateCallback(Action<Chunk> callback){
            cbOnActivate += callback;
        }
    }
Cheetahmoo
  • 13
  • 5
  • 1
    See LINQ / IEnumerable “Contains” or “Any” for a start. – user2864740 Oct 11 '19 at 01:16
  • You'll want Linq, but rather `Intersect` in the form of `ListA = ListA.Intersect(ListB)` See https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/set-operations – Immersive Oct 11 '19 at 03:16

3 Answers3

0

Here's one way.

The following code will change Active to false for chunks in activeChunks that are not found in chunks.

I assumed:

  • chunks in both lists have an Id property
  • there are not chunks in activeChunks with Active==false that you want to keep.
var chunksInActiveChunksThatDontExistInChunks = 
    activechunks.Where( ch => !chunks.Any( ch => ch.Id == chunk.Id ));

// Since it seems you're not familiar with Linq
// please be aware that this will not be evaluated until foreach is executed
// You can evaluate it earlier by calling ToList() 
// e.g. var chunksIn... = activechunks.Where(...).ToList();


foreach( var chunk in chunksInActiveChunksThatDontExistInChunks )
{
    chunk.Active = false;
}

activeChunks.RemoveAll(x => x.Active == false);

You could use Contains if your object match, but I don't know if they do so I went with .Id. It could be:

var chunksInActiveChunksThatDontExistInChunks = 
    activechunks.Where( ch => !chunks.Contains(ch));

For

//After Removing Chunks That do not exist in "chunks" add from chunks to ActiveChunks What is not In already in Chunks

you could:

var chunksThatAreInChunksButNotInActiveChunks = 
    chunks.Where( ch => !activeChunks.Any( ch => ch.Id == chunk.Id ));

activeChunks.AddRange(chunksThatAreInChunksButNotInActiveChunks);

Please note that this not good if the lists are modified by others while this is being executed.

tymtam
  • 31,798
  • 8
  • 86
  • 126
  • What does "ch" stand For? + Chunk does not have an "Id" – Cheetahmoo Oct 11 '19 at 01:25
  • In this context `ch` stands For the element in `activechunks` that is currently being processed in the Linq operation (`Where`). – tymtam Oct 11 '19 at 01:37
  • 2
    `activechunks.Except(chunks)` – Cory Nelson Oct 11 '19 at 02:06
  • Could you please include the declaration for Chunk? If might be important to understand how to compare them, as @tymtam noted here, he had to assume how to compare two Chunks. – Luc Oct 11 '19 at 02:08
  • @CoryNelson yeah, I too was thinking of .Except() and also since it needs an IEqualityComparer, it might be possible to call a function inside Equals() of GetHashCode(). – Luc Oct 11 '19 at 02:10
  • @tymtam Does this make it more efficient than what I have. I read that behind the scenes it's doing close to the same thing is that correct or did I misunderstand something? – Cheetahmoo Oct 11 '19 at 13:12
0
var missing = ActiveChunks.Where(i => !chunks.Contains(i));
missing.ToList().ForEach(i => Console.WriteLine(i));
var activeMinusMissing = ActiveChunks.Where(i => missing.Contains(i));
ActiveChunks = activeMinusMissing;

missing is a list which contains items that were in ActiveChunks but are missing from chunks (e.g. the ones you want removed)

the Console.WriteLine() can be any function you like and it is run on each item to be removed

activeMinusMissing is a list that contains the items from ActiveChunks minus the items to be removed (e.g. the ones in ActiveChunks but not in chunks).
Instead of removing the items from ActiveChunks, you can just replace ActiveChunks with activeMinusMissing.

The activeMinusMissing variable is just for demonstration so you can replace the last two lines with

ActiveChunks= ActiveChunks.Where(i => missing.Contains(i)).ToList();

So the final code would be

var missing = ActiveChunks.Where(i => !chunks.Contains(i));
missing.ToList().ForEach(i => Console.WriteLine(i));
ActiveChunks= ActiveChunks.Where(i => missing.Contains(i)).ToList();
-1

according to your code,i think, activechunks is finally the same chunks. No need to add and remove element. remove all activechunks element and add all chunks's element into activechunks.

Byoung Sam Moon
  • 306
  • 2
  • 6