Return a gameObject from LINQ .GroupBy()

I’ve got a list of gameObjects and I want to track the unique objects in the list as well as the count of each unique object. I’m trying to accomplish this by using LINQ and doing two different things: first, return the unique gameObjects as gameObjects and second I need to keep track of the count of each type of gameObject.

More specifically, I’ve got a list of troops and there are many different types of troops. In the UI I want to keep track of the type of troop and the current number of them on the battlefield like so:

For the image above the gameObject list would be 100 gameObjects where 25 are soldiers, 25 are archers, and 50 are cavalry troops.

My idea is to return the unique gameObjects from that list using .Distinct() so I know how many different types of troops there are and can .GetComponent and grab their sprites. Then I need to count how many of each unique game object there are for the troop totals.

Every time a troop is added or removed from the list, a function in the UI manager gets called to update the totals. I’m trying to use LINQ queries and I just can’t figure out how to return a gameObject when I use .GroupBy().

// BattleManager.cs (singleton)

// Gets updated every time a player troop is spawned or despawned
public List<GameObject> playerTroops;

// UITroopCounter.cs

    public GameObject troopCountPrefab;
    private int _uniqueTroopCount = 0;

    public void UpdateTroopCounts()
    {
        var _groupedTroops = BattleManager.Instance.playerTroops.Select(g => g.gameObject).GroupBy(g => g.name).ToList();

        if (_uniqueTroopCount != _groupedTroops.Count())
        {
            //Clean slate
            foreach (Transform child in transform)
                Destroy(child.gameObject);

            //Create a troopCounter object for each unique type of troop
            foreach (var troop in _groupedTroops)
            {
                var _newTroopCounter = Instantiate(troopCountPrefab, transform).GetComponent<UITroopCount>();
                _newTroopCounter.icon = troop.GetComponent<TroopCore>().icon;
                _newTroopCounter.counter = troop.Count();
            }
        }
        //Once these objects are created, I need some way to keep them attached to the count of the type of troop they are
        //Troops can be revived and new types of troops can be summoned during the battle as well
    }
}

Even though I’m doing .Select(g => g.gameObject) it comes back in a format I can’t use .GetComponent on. Seriously, if there’s a better way please let me know because this is feeling pretty squirrely at this point. Thanks!

I modified your code a bit. At first I rewrote _groupTroops. I will do my best to explain it. I will stick to your assumptions: 25 x soldiers, 25 x archers, 50 x cavalry. So, _groupTroops is a List of anonymous objects. The count of the _groupTroops is 3 - one unique troop. Each anonymous object have three fields, it’s just like class of this sort:

public class Troop{
	public string name;
	public int count;
	public List<GameObject> gameObject;
}
  • name - is the name of the unique troop (soldier, archer, cavalry)
  • count - is the number of GameObjects (so, for soldiers it will be 25, and 50 for cavalry)
  • gameObject - is the list of references to each GameObject of the specified troop. So, if there are 25 soldiers, then you will find here 25 references to those GameObjects.
  • To iterate through _groupTroops, you have to do something like that (there is string “s”. It contains the result):
    `

    	string s = string.Empty;
    	
    	for(int i = 0; i < _groupedTroops.Count; i++){
    		
    		string name = _groupedTroops*.name;*
    

    int count = _groupedTroops*.count;*

    * s += name + ": " + count + "
    ";*

    for (int j = 0; j < _groupedTroops*.gameObject.Count; j++){*

    GameObject go = _groupedTroops*.gameObject[j];*

    * s += " " + go + "
    ";*

    * }*
    * }*
    `
    Ok. Here you have your UITroopCounter class code. I reproduced your project, and when it comes to me, I can guarantee that it works. Enjoy!
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.Linq;

    public class UITroopCounter : MonoBehaviour
    *{ *
    * public GameObject troopCountPrefab;*
    * private int _uniqueTroopCount = 0;*

    * public void UpdateTroopCounts(){*

    * var groupedTroops =*
    * BattleManager.Instance.playerTroops*
    * .GroupBy(troop => troop.name)
    .Select(troop =>
    new {
    name = troop.Key,
    count = troop.Count(),
    gameObject = troop*

    * }
    )
    .Select(troop =>
    new{
    name = troop.name,
    count = troop.count,
    gameObject = troop.gameObject.ToList()
    }
    )
    .ToList();*_

    * int _groupedTroopsCount = _groupedTroops.Count;*

    * if (_uniqueTroopCount != _groupedTroopsCount){*

    * foreach (Transform child in transform)*
    * Destroy(child.gameObject);*

    * foreach(var troop in _groupedTroops){*

    * var _newTroopCounter = Instantiate(troopCountPrefab, transform).GetComponent();*

    * _newTroopCounter.icon = troop.gameObject.First().GetComponent().icon;*

    * _newTroopCounter.counter = troop.count;*

    * }*
    * }*

    * }*
    }