Yes, there are some scripts that do that, e.g.:
http://www.hiveworkshop.com/forums/graveyard-418/snippet-unitll-209540/
You can't say which is better, though--it depends on what it is used for. Usually you'll have three main choices: (1) use a unit array (2) use a linked list (3) use a unit group.
(1) is pretty standard. You just need an integer to keep track of the size, and then insertion is O(1) on the back (O(N) anywhere else if you want to preserve order). However, removal is O(N) assuming you don't want gaps--so if you want to remove a particular unit from the array, this isn't that good of an option. Clearing is O(N) if you really want to set all the members to point to null, but it is O(1) if you just reduce the size down to 0 (and when you iterate, you would only loop up to size). You waste memory that way though.
(2) Linked lists are nice in the sense that insertion is O(1) and removing a particular unit is O(1). It is slightly slower/more memory than the array method, but it has its perks.
(3) Groups... well you already know about groups. The difference is the enumeration. If you're just trying to store units (e.g. you're only using GroupAddUnit and GroupRemoveUnit) then option (1) or (2) is usually sufficient. However, groups can still win over in some cases--such as when you need to maintain multiple "groups" or "lists". Due to the 8191 limit, using a linked list or an array can easily become complicated if you need to support many individual "groups". With unit groups, you can simply make a group array. With option (1) or (2), it is less trivial since you need to partition the array accordingly and keep track of extra stuff.
Therefore, (1) and (2) are good options when you need something fast, reliable, and with a limited amount of "groups". For everything else, you're most likely better off using groups. Still, these are just general guidelines. They may not be concrete--and I may not have thought of all the cases.