Wasteful, equidigital and frugal numbers

Let n be a positive integer and l(n) be the number of its digits in base b.

Task
Wasteful, equidigital and frugal numbers
You are encouraged to solve this task according to the task description, using any language you may know.
Definitions

Express n as the product of its prime factors raised to the appropriate powers. Let D(n) be the total number of its base b digits in all its prime factors and in all their exponents that are greater than 1.

Then n is defined to be:

1. a wasteful (or extravagant) number if l(n) < D(n); or

2. an equidigital number if l(n) = D(n); or

3. a frugal (or economical) number if l(n) > D(n)

in base b.

By convention, the number 1 is considered to be an equidigital number in any base even though it has no prime factors.

For the avoidance of any doubt, the number 0 is not a positive integer (and arguably not a natural number either) and so is excluded from all 3 categories.

An economical number is sometimes defined as being one for which l(n) >= D(n) though this usage won't be followed here.


Examples

In base 10, the number 30 has a prime factorization of 2 x 3 x 5. The total number of digits is 3 (all exponents being 1) which is more than the 2 digits 30 has. So 30 is wasteful in base 10.

In base 10, the number 49 has a prime factorization of 7². The total number of digits, including those of the exponent, is 2 which is the same as the 2 digits 49 has. So 49 is equidigital in base 10.

In base 10, the number 125 has a prime factorization of 5³. The total number of digits, including those of the exponent, is 2 which is less than the 3 digits 125 has. So 125 is frugal in base 10.

In base 2, the number 100000 (32 decimal) has a prime factorization of 10^101 (2^5 decimal). The total number of binary digits, including those of the exponent, is 5 which is less than the 6 binary digits 100000 has. So 32 is frugal in base 2 (but equidigital in base 10).


Task

Compute and show here the first 50 and the 10,000th number in base 10 for each of the three categories of number defined above.

Also compute and show how many numbers less than 1,000,000 fall into each of the three categories.


Bonus

Do the same for base 11, but show the results in base 10.


References



C++

#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>

enum Category { WASTEFUL, EQUIDIGITAL, FRUGAL };
const std::vector<Category> categories = { Category::WASTEFUL, Category::EQUIDIGITAL, Category::FRUGAL };

struct Count {
	uint32_t lower_count;
	uint32_t upper_count;
};

std::vector<std::unordered_map<uint32_t,uint32_t>> factors;

std::string to_string(const Category& category) {
	std::string result;
	switch ( category ) {
		case Category::WASTEFUL    : result = "wasteful";    break;
		case Category::EQUIDIGITAL : result = "equidigital"; break;
		case Category::FRUGAL      : result = "frugal";      break;
	}
	return result;
}

/**
 * Return the number of digits in the given number written in the given base
 */
uint32_t digit_count(uint32_t number, const uint32_t& base) {
	uint32_t result = 0;
	while ( number != 0 ) {
		result++;
		number /= base;
	}
	return result;
}

/**
 * Return the total number of digits used in the prime factorisation
 * of the given number written in the given base
 */
uint32_t factor_count(const uint32_t& number, const uint32_t& base) {
	uint32_t result = 0;
	for ( const auto& [key, value] : factors[number] ) {
		result += digit_count(key, base);
		if ( value > 1 ) {
			result += digit_count(value, base);
		}
	}
	return result;
}

/**
 * Return the category of the given number written in the given base
 */
Category category(const uint32_t& number, const uint32_t& base) {
	const uint32_t digit = digit_count(number, base);
	const uint32_t factor = factor_count(number, base);
	return ( digit < factor ) ? Category::WASTEFUL :
		   ( digit > factor ) ? Category::FRUGAL : Category::EQUIDIGITAL;
}

/**
 * Factorise the numbers from 1 (inclusive) to limit (exclusive)
 */
void create_factors(const uint32_t& limit) {
	factors.assign(limit, std::unordered_map<uint32_t, uint32_t>());
	factors[1].emplace(1, 1);

	for ( uint32_t n = 1; n < limit; ++n ) {
		if ( factors[n].empty() ) {
			uint64_t n_copy = n;
			while ( n_copy < limit ) {
				for ( uint64_t i = n_copy; i < limit; i += n_copy ) {
					if ( factors[i].find(n) == factors[i].end() ) {
						factors[i].emplace(n, 1);
					} else {
						factors[i][n]++;
					}
				}
				n_copy *= n;
			}
		}
	}
}

int main() {
	create_factors(2'700'000);

	const uint32_t tiny_limit = 50;
	const uint32_t lower_limit = 10'000;
	const uint32_t upper_limit = 1'000'000;

	for ( uint32_t base : { 10, 11 } ) {
		std::unordered_map<Category, Count> counts = { { Category::WASTEFUL, Count(0, 0) },
			{ Category::EQUIDIGITAL, Count(0, 0) }, { Category::FRUGAL, Count(0,0) } };

		std::unordered_map<Category, std::vector<uint32_t>> lists = { { Category::WASTEFUL, std::vector<uint32_t>() },
			{ Category::EQUIDIGITAL, std::vector<uint32_t>() }, { Category::FRUGAL, std::vector<uint32_t>() } };

		uint32_t number = 1;
		std::cout << "FOR BASE " << base << ":" << std::endl << std::endl;
		while ( std::any_of(counts.begin(), counts.end(),
				[](const std::pair<Category, Count>& pair) { return pair.second.lower_count < lower_limit; }) ) {
			Category cat = category(number, base);
			if ( counts[cat].lower_count < tiny_limit || counts[cat].lower_count == lower_limit - 1 ) {
				lists[cat].emplace_back(number);
			}
			counts[cat].lower_count++;
			if ( number < upper_limit ) {
				counts[cat].upper_count++;
			}
			number++;
		}

		for ( const Category& category : categories ) {
			std::cout << "First " << tiny_limit << " " + to_string(category) << " numbers:" << std::endl;
			for ( uint32_t i = 0; i < tiny_limit; ++i ) {
				std::cout << std::setw(4) << lists[category][i] << ( i % 10 == 9 ? "\n" : " " );
			}
			std::cout << std::endl;
			std::cout << lower_limit << "th " << to_string(category) << " number: "
					  << lists[category][tiny_limit] << std::endl << std::endl;
		}

		std::cout << "For natural numbers less than " << upper_limit << ", the breakdown is as follows:" << std::endl;
		std::cout << "    Wasteful numbers    : " << counts[Category::WASTEFUL].upper_count << std::endl;
		std::cout << "    Equidigital numbers : " << counts[Category::EQUIDIGITAL].upper_count << std::endl;
		std::cout << "    Frugal numbers      : " << counts[Category::FRUGAL].upper_count << std::endl << std::endl;
	}
}
Output:
FOR BASE 10:

First 50 wasteful numbers:
   4    6    8    9   12   18   20   22   24   26
  28   30   33   34   36   38   39   40   42   44
  45   46   48   50   51   52   54   55   56   57
  58   60   62   63   65   66   68   69   70   72
  74   75   76   77   78   80   82   84   85   86

10000th wasteful number: 14346

First 50 equidigital numbers:
   1    2    3    5    7   10   11   13   14   15
  16   17   19   21   23   25   27   29   31   32
  35   37   41   43   47   49   53   59   61   64
  67   71   73   79   81   83   89   97  101  103
 105  106  107  109  111  112  113  115  118  119

10000th equidigital number: 33769

First 50 frugal numbers:
 125  128  243  256  343  512  625  729 1024 1029
1215 1250 1280 1331 1369 1458 1536 1681 1701 1715
1792 1849 1875 2048 2187 2197 2209 2401 2560 2809
3125 3481 3584 3645 3721 4096 4374 4375 4489 4802
4913 5041 5103 5329 6241 6250 6561 6859 6889 7203

10000th frugal number: 1953125

For natural numbers less than 1000000, the breakdown is as follows:
    Wasteful numbers    : 831231
    Equidigital numbers : 165645
    Frugal numbers      : 3123

FOR BASE 11:

First 50 wasteful numbers:
   4    6    8    9   10   12   18   20   22   24
  26   28   30   33   34   36   38   39   40   42
  44   45   46   48   50   51   52   54   55   56
  57   58   60   62   63   65   66   68   69   70
  72   74   75   76   77   78   80   82   84   85

10000th wasteful number: 12890

First 50 equidigital numbers:
   1    2    3    5    7   11   13   14   15   16
  17   19   21   23   25   27   29   31   32   35
  37   41   43   47   49   53   59   61   64   67
  71   73   79   81   83   89   97  101  103  107
 109  113  121  122  123  127  129  131  133  134

10000th equidigital number: 33203

First 50 frugal numbers:
 125  128  243  256  343  512  625  729 1024 1331
1369 1458 1536 1681 1701 1715 1792 1849 1875 2048
2187 2197 2209 2401 2560 2809 3072 3125 3481 3584
3645 3721 4096 4374 4375 4489 4802 4913 5041 5103
5120 5329 6241 6250 6561 6859 6889 7168 7203 7921

10000th frugal number: 2659171

For natural numbers less than 1000000, the breakdown is as follows:
    Wasteful numbers    : 795861
    Equidigital numbers : 200710
    Frugal numbers      : 3428

F#

// Frugal, equidigital, and wasteful numbers. Nigel Galloway: July 26th., 2022
let rec fG n g=match g/10L with 0L->n+1 |g->fG(n+1) g
let fN(g:int64)=Open.Numeric.Primes.Extensions.PrimeExtensions.PrimeFactors g|>Seq.skip 1|>Seq.countBy id|>Seq.sumBy(fun(n,g)->fG 0 n + if g<2 then 0 else fG 0 g)
let Frugal,Equidigital,Wasteful=let FEW n=Seq.initInfinite((+)2)|>Seq.filter(fun g->n(fG 0 g)(fN g)) in (("Frugal",FEW(>)),("Equidigital",seq{yield 1; yield! FEW(=)}),("Wasteful",FEW(<)))
[Frugal;Equidigital;Wasteful]|>List.iter(fun(n,g)->printf $"%s{n}: 10 thousandth is %d{Seq.item 9999 g}; There are %d{Seq.length (g|>Seq.takeWhile((>)1000000))} < 1 million\n First 50: "; g|>Seq.take 50|>Seq.iter(printf "%d "); printfn "")
Output:
Frugal: 10 thousandth is 1953125; There are 3123 < 1 million
 First 50: 125 128 243 256 343 512 625 729 1024 1029 1215 1250 1280 1331 1369 1458 1536 1681 1701 1715 1792 1849 1875 2048 2187 2197 2209 2401 2560 2809 3125 3481 3584 3645 3721 4096 4374 4375 4489 4802 4913 5041 5103 5329 6241 6250 6561 6859 6889 7203
Equidigital: 10 thousandth is 33769; There are 165645 < 1 million
 First 50: 1 2 3 5 7 10 11 13 14 15 16 17 19 21 23 25 27 29 31 32 35 37 41 43 47 49 53 59 61 64 67 71 73 79 81 83 89 97 101 103 105 106 107 109 111 112 113 115 118 119
Wasteful: 10 thousandth is 14346; There are 831231 < 1 million
 First 50: 4 6 8 9 12 18 20 22 24 26 28 30 33 34 36 38 39 40 42 44 45 46 48 50 51 52 54 55 56 57 58 60 62 63 65 66 68 69 70 72 74 75 76 77 78 80 82 84 85 86

J

Brute force implementation:
I=: #@(#.inv)"0
D=:  [ +/@:I __ -.&1@,@q: ]
typ=: ~:&1@] * *@(I-D)"0 NB. _1: wasteful, 0: equidigital, 1: frugal
Task examples (base 10):
   (9999&{, 50&{.)1+I._1=b10 NB. wasteful
14346 4 6 8 9 12 18 20 22 24 26 28 30 33 34 36 38 39 40 42 44 45 46 48 50 51 52 54 55 56 57 58 60 62 63 65 66 68 69 70 72 74 75 76 77 78 80 82 84 85 86
   (9999&{, 50&{.)1+I. 0=b10 NB. equidigital
33769 1 2 3 5 7 10 11 13 14 15 16 17 19 21 23 25 27 29 31 32 35 37 41 43 47 49 53 59 61 64 67 71 73 79 81 83 89 97 101 103 105 106 107 109 111 112 113 115 118 119
   (9999&{, 50&{.)1+I. 1=b10 NB. frugal
1953125 125 128 243 256 343 512 625 729 1024 1029 1215 1250 1280 1331 1369 1458 1536 1681 1701 1715 1792 1849 1875 2048 2187 2197 2209 2401 2560 2809 3125 3481 3584 3645 3721 4096 4374 4375 4489 4802 4913 5041 5103 5329 6241 6250 6561 6859 6889 7203
   +/1e6>1+I._1=b10 NB. wasteful
831231
   +/1e6>1+I. 0=b10 NB. equidigital
165645
   +/1e6>1+I. 1=b10 NB. frugal
3123
Task examples (base 11):
   (9999&{, 50&{.)1+I._1=b11 NB. wasteful
12890 4 6 8 9 10 12 18 20 22 24 26 28 30 33 34 36 38 39 40 42 44 45 46 48 50 51 52 54 55 56 57 58 60 62 63 65 66 68 69 70 72 74 75 76 77 78 80 82 84 85
   (9999&{, 50&{.)1+I. 0=b11 NB. equidigital
33203 1 2 3 5 7 11 13 14 15 16 17 19 21 23 25 27 29 31 32 35 37 41 43 47 49 53 59 61 64 67 71 73 79 81 83 89 97 101 103 107 109 113 121 122 123 127 129 131 133 134
   (9999&{, 50&{.)1+I. 1=b11 NB. frugal
2659171 125 128 243 256 343 512 625 729 1024 1331 1369 1458 1536 1681 1701 1715 1792 1849 1875 2048 2187 2197 2209 2401 2560 2809 3072 3125 3481 3584 3645 3721 4096 4374 4375 4489 4802 4913 5041 5103 5120 5329 6241 6250 6561 6859 6889 7168 7203 7921
   +/1e6>1+I._1=b11 NB. wasteful
795861
   +/1e6>1+I. 0=b11 NB. equidigital
200710
   +/1e6>1+I. 1=b11 NB. frugal
3428

Java

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public final class WastefulEquidigitalAndFrugalNumbers {

	public static void main(String[] args) {
		createFactors(2_700_000);
		
		final int tinyLimit = 50;
		final int lowerLimit = 10_000;
		final int upperLimit = 1_000_000;		
		
		for ( int base : List.of( 10, 11 ) ) {				
			Map<Category, Count> counts = Arrays.stream(Category.values())
				.collect(Collectors.toMap( Function.identity(), value -> new Count(0, 0) ));
			Map<Category, List<Integer>> lists = Arrays.stream(Category.values())
				.collect(Collectors.toMap( Function.identity(), value -> new ArrayList<Integer>() ));		
			
		    int number = 1;
		    System.out.println("FOR BASE " + base + ":" + System.lineSeparator());
		    while ( counts.values().stream().anyMatch( count -> count.lowerCount < lowerLimit ) ) {
		    	Category category = category(number, base);
		    	Count count = counts.get(category);
		    	if ( count.lowerCount < tinyLimit || count.lowerCount == lowerLimit - 1 ) {
		    		lists.get(category).add(number);
		    	}
		    	count.lowerCount += 1;
		    	if ( number < upperLimit ) {
		    		count.upperCount += 1;
		    	}
		    	number += 1;		    	
		    }		
		
			for ( Category category : Category.values() ) {
				System.out.println("First " + tinyLimit + " " + category + " numbers:");
				for ( int i = 0; i < tinyLimit; i++ ) {
					System.out.print(String.format("%4d%s", lists.get(category).get(i), (i % 10 == 9 ? "\n" : " ")));
				}
			    System.out.println();		   
			    System.out.println(lowerLimit + "th " + category + " number: " + lists.get(category).get(tinyLimit));
			    System.out.println();
			}
			
		    System.out.println("For natural numbers less than " + upperLimit + ", the breakdown is as follows:");		    
		    System.out.println("    Wasteful numbers    : " + counts.get(Category.Wasteful).upperCount);
		    System.out.println("    Equidigital numbers : " + counts.get(Category.Equidigital).upperCount);
		    System.out.println("    Frugal numbers      : " + counts.get(Category.Frugal).upperCount);
		    System.out.println();	
		}
	}	
	
	private enum Category { Wasteful, Equidigital, Frugal }
	
	/**
	 * Factorise the numbers from 1 (inclusive) to limit (exclusive)
	 */
	private static void createFactors(int limit) {
		factors = IntStream.rangeClosed(0, limit).boxed()
			.map( integer -> new HashMap<Integer, Integer>() ).collect(Collectors.toList());
		factors.get(1).put(1, 1);
		
		for ( int n = 1; n < limit; n++ ) {
			if ( factors.get(n).isEmpty() ) {
				long nCopy = n;
				while ( nCopy < limit ) {
					for ( long i = nCopy; i < limit; i += nCopy ) {
						factors.get((int) i).merge(n, 1, Integer::sum);
					}
					nCopy *= n;
				}
			}
		}
	}
	
	/**
	 * Return the number of digits in the given number written in the given base 
	 */
	private static int digitCount(int number, int base) {
		int result = 0;
		while ( number != 0 ) {
		    result += 1;
		    number /= base;
		}
		return result;
	}
	
	/**
	 * Return the total number of digits used in the prime factorisation
	 * of the given number written in the given base
	 */
	private static int factorCount(int number, int base) {
		int result = 0;
		for ( Map.Entry<Integer, Integer> entry : factors.get(number).entrySet() ) {
			result += digitCount(entry.getKey(), base);
			if ( entry.getValue() > 1 ) {
				result += digitCount(entry.getValue(), base);
			}
		}
		return result;
	}
	
	/**
	 * Return the category of the given number written in the given base
	 */
	private static Category category(int number, int base) {
		final int digitCount = digitCount(number, base);
		final int factorCount = factorCount(number, base);
		return ( digitCount < factorCount ) ? Category.Wasteful :
			   ( digitCount > factorCount ) ? Category.Frugal : Category.Equidigital;	  
	}
	
	private static class Count {
		
		public Count(int aLowerCount, int aUpperCount) {
			lowerCount = aLowerCount; upperCount = aUpperCount;
		}
		
		private int lowerCount, upperCount;
		
	}
	
	private static List<Map<Integer, Integer>> factors;

}
Output:
FOR BASE 10:

First 50 Wasteful numbers:
   4    6    8    9   12   18   20   22   24   26
  28   30   33   34   36   38   39   40   42   44
  45   46   48   50   51   52   54   55   56   57
  58   60   62   63   65   66   68   69   70   72
  74   75   76   77   78   80   82   84   85   86

10000th Wasteful number: 14346

First 50 Equidigital numbers:
   1    2    3    5    7   10   11   13   14   15
  16   17   19   21   23   25   27   29   31   32
  35   37   41   43   47   49   53   59   61   64
  67   71   73   79   81   83   89   97  101  103
 105  106  107  109  111  112  113  115  118  119

10000th Equidigital number: 33769

First 50 Frugal numbers:
 125  128  243  256  343  512  625  729 1024 1029
1215 1250 1280 1331 1369 1458 1536 1681 1701 1715
1792 1849 1875 2048 2187 2197 2209 2401 2560 2809
3125 3481 3584 3645 3721 4096 4374 4375 4489 4802
4913 5041 5103 5329 6241 6250 6561 6859 6889 7203

10000th Frugal number: 1953125

For natural numbers less than 1000000, the breakdown is as follows:
    Wasteful numbers    : 831231
    Equidigital numbers : 165645
    Frugal numbers      : 3123

FOR BASE 11:

First 50 Wasteful numbers:
   4    6    8    9   10   12   18   20   22   24
  26   28   30   33   34   36   38   39   40   42
  44   45   46   48   50   51   52   54   55   56
  57   58   60   62   63   65   66   68   69   70
  72   74   75   76   77   78   80   82   84   85

10000th Wasteful number: 12890

First 50 Equidigital numbers:
   1    2    3    5    7   11   13   14   15   16
  17   19   21   23   25   27   29   31   32   35
  37   41   43   47   49   53   59   61   64   67
  71   73   79   81   83   89   97  101  103  107
 109  113  121  122  123  127  129  131  133  134

10000th Equidigital number: 33203

First 50 Frugal numbers:
 125  128  243  256  343  512  625  729 1024 1331
1369 1458 1536 1681 1701 1715 1792 1849 1875 2048
2187 2197 2209 2401 2560 2809 3072 3125 3481 3584
3645 3721 4096 4374 4375 4489 4802 4913 5041 5103
5120 5329 6241 6250 6561 6859 6889 7168 7203 7921

10000th Frugal number: 2659171

For natural numbers less than 1000000, the breakdown is as follows:
    Wasteful numbers    : 795861
    Equidigital numbers : 200710
    Frugal numbers      : 3428

Julia

using Primes

"""
    function wastefulness(n, base = 10)
    
calculate d1: the number of digits in base `base` required to write the factor expansion of
`n`, ie 12 -> 2^2 * 3^2 is 4 digits, 7 -> 7 is 1 digit, 20 -> 5 * 2^2 is 3 digits

calculate d2: the number of digits in base `base` to represent `n` itself

return -1 if frugal (d1 > d2), 0 if equidigital (d1 == d2), 1 if wasteful (d1 > d2)
"""
function wastefulness(n::Integer, base = 10)
    @assert n > 0
    return n == 1 ? 0 : 
       sign(sum(p -> ndigits(p[1], base=base) + 
       (p[2] == 1 ? 0 : ndigits(p[2], base=base)),
       factor(n).pe) - 
       ndigits(n, base=base))
end

for b in [10, 11]
    w50, e50, f50 = Int[], Int[], Int[]
    w10k, e10k, f10k, wcount, ecount, fcount, wm, em, fm = 0, 0, 0, 0, 0, 0, 0, 0, 0
    for n in 1:10_000_000
        sgn = wastefulness(n, b)
        if sgn < 0
            fcount < 50 && push!(f50, n)
            fcount += 1
            fcount == 10000 &&(f10k = n)
            n < 1_000_000 && (fm += 1)
        elseif sgn == 0
            ecount < 50 && push!(e50, n)
            ecount += 1
            ecount == 10000 && (e10k = n)
            n < 1_000_000 && (em += 1)
        else # sgn > 0
            wcount < 50 && push!(w50, n)
            wcount += 1
            wcount == 10000  && (w10k = n)
            n < 1_000_000 && (wm += 1)
        end
        if f10k > 0
            println("FOR BASE $b:\n")
            println("First 50 Wasteful numbers:")
            foreach(p -> print(rpad(p[2], 5), p[1] % 10 == 0 ? "\n" : ""), pairs(w50))
            println("\nFirst 50 Equidigital numbers:")
            foreach(p -> print(rpad(p[2], 5), p[1] % 10 == 0 ? "\n" : ""), pairs(e50))
            println("\nFirst 50 Frugal numbers:")
            foreach(p -> print(rpad(p[2], 5), p[1] % 10 == 0 ? "\n" : ""), pairs(f50))
            println("\n10,000th Wasteful number   : $w10k")
            println("10,000th Equidigital number  : $e10k")
            println("10,000th Frugal number       : $f10k")
            println("\nFor natural numbers < 1 million, the breakdown is as follows:")
            println("  Wasteful numbers    : $wm")
            println("  Equidigital numbers : $em")
            println("  Frugal numbers      : $fm\n\n")
            break
        end
    end
end

Output is the same as Wren example.

Mathematica/Wolfram Language

ClearAll[FactorIntegerDigits, ID, Stats]
FactorIntegerDigits[n_] := Module[{},
  fi = FactorInteger[n];
  fi[[All, 1]] //= Map[IntegerLength];
  fi[[All, 2]] //= Map[If[# == 1, 0, IntegerLength[#]] &];
  Total[Flatten[fi]]
  ]
Stats[l_List] := Module[{},
  Print["10000: ", l[[10^4]]];
  Print["First 50: ", l[[;; 50]]];
  Print["Below 10^6: ", Length[Select[l, LessThan[10^6]]]];
  ]
ID[n_] := {IntegerLength[n], FactorIntegerDigits[n]}
bla = {#, ID[#]} & /@ Range[2000000];
wasteful = Select[bla, #[[2, 1]] < #[[2, 2]] &][[All, 1]];
equidigital = Select[bla, #[[2, 1]] == #[[2, 2]] &][[All, 1]];
frugal = Select[bla, #[[2, 1]] > #[[2, 2]] &][[All, 1]];
Print["Wasteful"]
Stats[wasteful]

Print["Equidigital"]
Stats[equidigital]

Print["Frugal"]
Stats[frugal]
Output:
Wasteful
10000: 14346
First 50: {4,6,8,9,12,18,20,22,24,26,28,30,33,34,36,38,39,40,42,44,45,46,48,50,51,52,54,55,56,57,58,60,62,63,65,66,68,69,70,72,74,75,76,77,78,80,82,84,85,86}
Below 10^6: 831231

Equidigital
10000: 33769
First 50: {1,2,3,5,7,10,11,13,14,15,16,17,19,21,23,25,27,29,31,32,35,37,41,43,47,49,53,59,61,64,67,71,73,79,81,83,89,97,101,103,105,106,107,109,111,112,113,115,118,119}
Below 10^6: 165645

Frugal
10000: 1953125
First 50: {125,128,243,256,343,512,625,729,1024,1029,1215,1250,1280,1331,1369,1458,1536,1681,1701,1715,1792,1849,1875,2048,2187,2197,2209,2401,2560,2809,3125,3481,3584,3645,3721,4096,4374,4375,4489,4802,4913,5041,5103,5329,6241,6250,6561,6859,6889,7203}
Below 10^6: 3123

Nim

import std/[sequtils, strformat, tables]

# Sieve to find the decomposition in prime factors.
const N = 2_700_000
var factors: array[1..N, CountTable[int]]
factors[1].inc(1)

for n in 2..N:
  if factors[n].len == 0:   # "n" is prime.
    var m = n               # Powers of "n"
    while m <= N:
      for k in countup(m, N, m):
        factors[k].inc(n)
      m *= n

type Category {.pure.} = enum Wasteful = "wasteful"
                              Equidigital = "equidigital"
                              Frugal = "frugal"

func digitCount(n, base: Positive): int =
  ## Return the number of digits of the representation of "n" in given base.
  var n = n.Natural
  while n != 0:
    inc result
    n = n div base

proc d(n, base: Positive): int =
  ## Compute "D(n)" in given base.
  for (p, e) in factors[n].pairs:
    inc result, p.digitCount(base)
    if e > 1: inc result, e.digitCount(base)

proc category(n, base: Positive): Category =
  ## Return the category of "n" in given base.
  let i = n.digitCount(base)
  let d = d(n, base)
  result = if i < d: Wasteful elif i > d: Frugal else: Equidigital


const N1 = 50
const N2 = 10_000
const Limit = 1_000_000

for base in [10, 11]:

  var counts1: array[Category, int]                   # Total counts.
  var counts2: array[Category, int]                   # Counts for n < Limit.
  var numbers1: array[Category, array[1..N1, int]]    # First N1 numbers in each category.
  var numbers2: array[Category, int]                  # Number at position N2 in each category.

  echo &"For base {base}."
  echo "===========\n"
  var n = 1
  while true:
    if n == Limit:
      counts2 = counts1
    let cat = n.category(base)
    inc counts1[cat]
    let c = counts1[cat]
    if c <= N1:
      numbers1[cat][c] = n
    elif c == N2:
      numbers2[cat] = n
    inc n
    if allIt(counts1, it >= N2) and n >= Limit: break

  for cat in Category.low..Category.high:
    echo &"First {N1} {cat} numbers:"
    for i, n in numbers1[cat]:
      stdout.write &"{n:4}"
      stdout.write if i mod 10 == 0: '\n' else: ' '
    echo &"\nThe {N2}th {cat} number is {numbers2[cat]}.\n"

  echo &"Among numbers less than {Limit}, there are:"
  for cat in Category.low..Category.high:
    echo &"- {counts2[cat]} {cat} numbers."
  echo '\n'
Output:
For base 10.
===========

First 50 wasteful numbers:
   4    6    8    9   12   18   20   22   24   26
  28   30   33   34   36   38   39   40   42   44
  45   46   48   50   51   52   54   55   56   57
  58   60   62   63   65   66   68   69   70   72
  74   75   76   77   78   80   82   84   85   86

The 10000th wasteful number is 14346.

First 50 equidigital numbers:
   1    2    3    5    7   10   11   13   14   15
  16   17   19   21   23   25   27   29   31   32
  35   37   41   43   47   49   53   59   61   64
  67   71   73   79   81   83   89   97  101  103
 105  106  107  109  111  112  113  115  118  119

The 10000th equidigital number is 33769.

First 50 frugal numbers:
 125  128  243  256  343  512  625  729 1024 1029
1215 1250 1280 1331 1369 1458 1536 1681 1701 1715
1792 1849 1875 2048 2187 2197 2209 2401 2560 2809
3125 3481 3584 3645 3721 4096 4374 4375 4489 4802
4913 5041 5103 5329 6241 6250 6561 6859 6889 7203

The 10000th frugal number is 1953125.

Among numbers less than 1000000, there are:
- 831231 wasteful numbers.
- 165645 equidigital numbers.
- 3123 frugal numbers.


For base 11.
===========

First 50 wasteful numbers:
   4    6    8    9   10   12   18   20   22   24
  26   28   30   33   34   36   38   39   40   42
  44   45   46   48   50   51   52   54   55   56
  57   58   60   62   63   65   66   68   69   70
  72   74   75   76   77   78   80   82   84   85

The 10000th wasteful number is 12890.

First 50 equidigital numbers:
   1    2    3    5    7   11   13   14   15   16
  17   19   21   23   25   27   29   31   32   35
  37   41   43   47   49   53   59   61   64   67
  71   73   79   81   83   89   97  101  103  107
 109  113  121  122  123  127  129  131  133  134

The 10000th equidigital number is 33203.

First 50 frugal numbers:
 125  128  243  256  343  512  625  729 1024 1331
1369 1458 1536 1681 1701 1715 1792 1849 1875 2048
2187 2197 2209 2401 2560 2809 3072 3125 3481 3584
3645 3721 4096 4374 4375 4489 4802 4913 5041 5103
5120 5329 6241 6250 6561 6859 6889 7168 7203 7921

The 10000th frugal number is 2659171.

Among numbers less than 1000000, there are:
- 795861 wasteful numbers.
- 200710 equidigital numbers.
- 3428 frugal numbers.

Perl

Library: ntheory
use v5.36;
use experimental 'for_list';
use ntheory <factor todigitstring>;
use List::Util <sum max min pairmap>;

sub table ($c, @V) { my $t = $c * (my $w = 6); ( sprintf( ('%'.$w.'d')x@V, @V) ) =~ s/.{1,$t}\K/\n/gr }

sub bag (@v) { my %h; $h{$_}++ for @v; %h }

for my $base (10, 11) {
    my(@F,@E,@W,$n,$totals);
    do {
        my %F = bag factor ++$n;
        my $s = sum pairmap { length(todigitstring($a,$base)) + ($b > 1 ? length(todigitstring($b,$base)) : 0) } %F;
        my $l = length todigitstring($n,$base);
        if    ($n == 1 or $l == $s) { push @E, $n }
        elsif (           $l <  $s) { push @W, $n }
        else                        { push @F, $n }
    } until 10000 < min scalar @F, scalar @E, scalar @W;

    say "In base $base:";
    for my ($type, $values) ('Wasteful', \@W, 'Equidigital', \@E, 'Frugal', \@F) {
        say "\n$type numbers:";
        say table 10, @$values[0..49];
        say "10,000th: $$values[9999]";
        $totals .= sprintf "%11s: %d\n", $type, scalar grep { $_ < 1_000_000 } @$values
    }
    say "\nOf the positive integers up to one million:\n$totals";
}
Output:
In base 10:

Wasteful numbers:
     4     6     8     9    12    18    20    22    24    26
    28    30    33    34    36    38    39    40    42    44
    45    46    48    50    51    52    54    55    56    57
    58    60    62    63    65    66    68    69    70    72
    74    75    76    77    78    80    82    84    85    86

10,000th: 14346

Equidigital numbers:
     1     2     3     5     7    10    11    13    14    15
    16    17    19    21    23    25    27    29    31    32
    35    37    41    43    47    49    53    59    61    64
    67    71    73    79    81    83    89    97   101   103
   105   106   107   109   111   112   113   115   118   119

10,000th: 33769

Frugal numbers:
   125   128   243   256   343   512   625   729  1024  1029
  1215  1250  1280  1331  1369  1458  1536  1681  1701  1715
  1792  1849  1875  2048  2187  2197  2209  2401  2560  2809
  3125  3481  3584  3645  3721  4096  4374  4375  4489  4802
  4913  5041  5103  5329  6241  6250  6561  6859  6889  7203

10,000th: 1953125

Of the positive integers up to one million:
   Wasteful: 831231
Equidigital: 165645
     Frugal: 3123

In base 11:

Wasteful numbers:
     4     6     8     9    10    12    18    20    22    24
    26    28    30    33    34    36    38    39    40    42
    44    45    46    48    50    51    52    54    55    56
    57    58    60    62    63    65    66    68    69    70
    72    74    75    76    77    78    80    82    84    85

10,000th: 12890

Equidigital numbers:
     1     2     3     5     7    11    13    14    15    16
    17    19    21    23    25    27    29    31    32    35
    37    41    43    47    49    53    59    61    64    67
    71    73    79    81    83    89    97   101   103   107
   109   113   121   122   123   127   129   131   133   134

10,000th: 33203

Frugal numbers:
   125   128   243   256   343   512   625   729  1024  1331
  1369  1458  1536  1681  1701  1715  1792  1849  1875  2048
  2187  2197  2209  2401  2560  2809  3072  3125  3481  3584
  3645  3721  4096  4374  4375  4489  4802  4913  5041  5103
  5120  5329  6241  6250  6561  6859  6889  7168  7203  7921

10,000th: 2659171

Of the positive integers up to one million:
   Wasteful: 795861
Equidigital: 200710
     Frugal: 3428

Phix

Translation of: Wren
with javascript_semantics
function analyze(integer n, b)
    sequence f = prime_factors(n,2,-1)
    integer digits = 0
    for pq in f do
        integer {p,q} = pq  
        digits += length(sprintf("%a",{{b,p}}))
        if q>1 then digits += length(sprintf("%a",{{b,q}})) end if
    end for
    -- -1/0/+1 => 1/2/3 for wasteful/equidigital/frugal:
    return compare(length(sprintf("%a",{{b,n}})), digits)+2
end function

constant fmt = """
FOR BASE %d:

First 50 Wasteful numbers:
%s
First 50 Equidigital numbers:
%s
First 50 Frugal numbers:
%s
10,000th Wasteful number    : %d
10,000th Equidigital number : %d
10,000th Frugal number      : %d

For natural numbers < 1 million, the breakdown is as follows:
  Wasteful numbers    : %6d
  Equidigital numbers : %6d
  Frugal numbers      : %6d

"""

for b in {10, 11} do
    sequence wef = {{},{1},{}},
             w10k = {0,0,0},
             c = {0,1,0},
             c2 = {0,1,0}
    integer n = 2
    atom t1 = time()+1
    while min(c) < 10000 do
        integer wdx = analyze(n, b)
        if length(wef[wdx])<50 then wef[wdx] &= n
        elsif c[wdx]=9999 then w10k[wdx]=n end if
        c[wdx] += 1
        if n<1e6 then c2[wdx] += 1 end if
        n += 1
        if time()>t1 then
            progress("working %d...",{n})
            t1 = time()+1
        end if
    end while
    progress("")
    sequence w3 = apply(true,join_by,{wef,1,10,{" "},{"\n"},{"%4d"}})
    printf(1,fmt,b&w3&w10k&c2)
end for

Output identical to Wren

Raku

use Prime::Factor;
use Lingua::EN::Numbers;

my %cache;

sub factor-char-sum ($n, $base = 10) { sum $n.&prime-factors.Bag.map: { .key.base($base).chars + (.value > 1 ?? .value.base($base).chars !! 0) } }

sub economical  ($n, $base = 10) { ($n >  1) && $n.base($base).chars >  (%cache{$base}[$n] //= factor-char-sum $n, $base) }
sub equidigital ($n, $base = 10) { ($n == 1) || $n.base($base).chars == (%cache{$base}[$n] //= factor-char-sum $n, $base) }
sub extravagant ($n, $base = 10) {              $n.base($base).chars <  (%cache{$base}[$n] //= factor-char-sum $n, $base) }


for 10, 11 -> $base {
    %cache{$base}[3e6] = Any; # preallocate to avoid concurrency issues
    say "\nIn Base $base:";
    for &extravagant, &equidigital, &economical -> &sub {
        say "\nFirst 50 {&sub.name} numbers:";
        say (^∞).grep( {.&sub($base)} )[^50].batch(10)».&comma».fmt("%6s").join: "\n";
        say "10,000th: " ~ (^∞).hyper(:2000batch).grep( {.&sub($base)} )[9999].&comma;
    }

    my $upto = 1e6.Int;
    my atomicint ($extravagant, $equidigital, $economical);
    say "\nOf the positive integers up to {$upto.&cardinal}:";
    (1..^$upto).race(:5000batch).map: { .&extravagant($base) ?? ++⚛$extravagant !! .&equidigital($base) ?? ++⚛$equidigital !! ++⚛$economical };
    say " Extravagant: {comma $extravagant}\n Equidigital: {comma $equidigital}\n  Economical: {comma $economical}";
    %cache{$base} = Empty;
}
Output:
In Base 10:

First 50 extravagant numbers:
     4      6      8      9     12     18     20     22     24     26
    28     30     33     34     36     38     39     40     42     44
    45     46     48     50     51     52     54     55     56     57
    58     60     62     63     65     66     68     69     70     72
    74     75     76     77     78     80     82     84     85     86
10,000th: 14,346

First 50 equidigital numbers:
     1      2      3      5      7     10     11     13     14     15
    16     17     19     21     23     25     27     29     31     32
    35     37     41     43     47     49     53     59     61     64
    67     71     73     79     81     83     89     97    101    103
   105    106    107    109    111    112    113    115    118    119
10,000th: 33,769

First 50 economical numbers:
   125    128    243    256    343    512    625    729  1,024  1,029
 1,215  1,250  1,280  1,331  1,369  1,458  1,536  1,681  1,701  1,715
 1,792  1,849  1,875  2,048  2,187  2,197  2,209  2,401  2,560  2,809
 3,125  3,481  3,584  3,645  3,721  4,096  4,374  4,375  4,489  4,802
 4,913  5,041  5,103  5,329  6,241  6,250  6,561  6,859  6,889  7,203
10,000th: 1,953,125

Of the positive integers up to one million:
 Extravagant: 831,231
 Equidigital: 165,645
  Economical: 3,123

In Base 11:

First 50 extravagant numbers:
     4      6      8      9     10     12     18     20     22     24
    26     28     30     33     34     36     38     39     40     42
    44     45     46     48     50     51     52     54     55     56
    57     58     60     62     63     65     66     68     69     70
    72     74     75     76     77     78     80     82     84     85
10,000th: 12,890

First 50 equidigital numbers:
     1      2      3      5      7     11     13     14     15     16
    17     19     21     23     25     27     29     31     32     35
    37     41     43     47     49     53     59     61     64     67
    71     73     79     81     83     89     97    101    103    107
   109    113    121    122    123    127    129    131    133    134
10,000th: 33,203

First 50 economical numbers:
   125    128    243    256    343    512    625    729  1,024  1,331
 1,369  1,458  1,536  1,681  1,701  1,715  1,792  1,849  1,875  2,048
 2,187  2,197  2,209  2,401  2,560  2,809  3,072  3,125  3,481  3,584
 3,645  3,721  4,096  4,374  4,375  4,489  4,802  4,913  5,041  5,103
 5,120  5,329  6,241  6,250  6,561  6,859  6,889  7,168  7,203  7,921
10,000th: 2,659,171

Of the positive integers up to one million:
 Extravagant: 795,861
 Equidigital: 200,710
  Economical: 3,428

RPL

Works with: HP version 49
≪ DUP SIZE SWAP
   FACTORS 0
   1 3 PICK SIZE FOR j
      OVER j GET
      IF DUP 1 == THEN DROP ELSE SIZE + END
   NEXT
   NIP - SIGN 
≫ 'WEF?' STO

≪ 1 → t j
  ≪ t {} {1} IFTE 
     WHILE DUP SIZE 50 < REPEAT
       IF 'j' INCR WEF? t == THEN j + END
     END
≫ ≫ 'TASK' STO
-1 TASK 0 TASK 1 TASK 
Output:
3: {4 6 8 9 12 18 20 22 24 26 28 30 33 34 36 38 39 40 42 44 45 46 48 50 51 52 54 55 56 57 58 60 62 63 65 66 68 69 70 72 74 75 76 77 78 80 82 84 85 86}
2: {1 2 3 5 7 10 11 13 14 15 16 17 19 21 23 25 27 29 31 32 35 37 41 43 47 49 53 59 61 64 67 71 73 79 81 83 89 97 101 103 105 106 107 109 111 112 113 115 118 119}
1: { 125 128 243 256 343 512 625 729 1024 1029 1215 1250 1280 1331 1369 1458 1536 1681 1701 1715 1792 1849 1875 2048 2187 2197 2209 2401 2560 2809 3125 3481 3584 3645 3721 4096 4374 4375 4489 4802 4913 5041 5103 5329 6241 6250 6561 6859 6889 7203}

Ruby

require 'prime'

[10,11].each do |base|
  res = Hash.new{|h, k| h[k] = [] }
  puts "\nBase: #{base}"

  (1..).each do |n|
    pd = n.prime_division
    pd = pd.map{|pr| pr.pop if pr.last == 1; pr}
    pd = [1] if n == 1
    selector = n.digits(base).size <=> pd.flatten.sum{|m| m.digits(base).size} # -1,0,1
    res[[:Equidigital, :Frugal, :Wasteful][selector]] << n
    break if res.values.all?{|v| v.size >= 10000}
  end

  res.each do |k, v|
    puts "#{k}:"
    puts "10000th: #{v[9999]}; count: #{v.count{|n| n < 1_000_000}}"
    p v.first(50)
  end
end
Output:
Base: 10
Equidigital:
10000st: 33769 count: 165645
[1, 2, 3, 5, 7, 10, 11, 13, 14, 15, 16, 17, 19, 21, 23, 25, 27, 29, 31, 32, 35, 37, 41, 43, 47, 49, 53, 59, 61, 64, 67, 71, 73, 79, 81, 83, 89, 97, 101, 103, 105, 106, 107, 109, 111, 112, 113, 115, 118, 119]
Wasteful:
10000st: 14346 count: 831231
[4, 6, 8, 9, 12, 18, 20, 22, 24, 26, 28, 30, 33, 34, 36, 38, 39, 40, 42, 44, 45, 46, 48, 50, 51, 52, 54, 55, 56, 57, 58, 60, 62, 63, 65, 66, 68, 69, 70, 72, 74, 75, 76, 77, 78, 80, 82, 84, 85, 86]
Frugal:
10000st: 1953125 count: 3123
[125, 128, 243, 256, 343, 512, 625, 729, 1024, 1029, 1215, 1250, 1280, 1331, 1369, 1458, 1536, 1681, 1701, 1715, 1792, 1849, 1875, 2048, 2187, 2197, 2209, 2401, 2560, 2809, 3125, 3481, 3584, 3645, 3721, 4096, 4374, 4375, 4489, 4802, 4913, 5041, 5103, 5329, 6241, 6250, 6561, 6859, 6889, 7203]

Base: 11
Equidigital:
10000st: 33203 count: 200710
[1, 2, 3, 5, 7, 11, 13, 14, 15, 16, 17, 19, 21, 23, 25, 27, 29, 31, 32, 35, 37, 41, 43, 47, 49, 53, 59, 61, 64, 67, 71, 73, 79, 81, 83, 89, 97, 101, 103, 107, 109, 113, 121, 122, 123, 127, 129, 131, 133, 134]
Wasteful:
10000st: 12890 count: 795861
[4, 6, 8, 9, 10, 12, 18, 20, 22, 24, 26, 28, 30, 33, 34, 36, 38, 39, 40, 42, 44, 45, 46, 48, 50, 51, 52, 54, 55, 56, 57, 58, 60, 62, 63, 65, 66, 68, 69, 70, 72, 74, 75, 76, 77, 78, 80, 82, 84, 85]
Frugal:
10000st: 2659171 count: 3428
[125, 128, 243, 256, 343, 512, 625, 729, 1024, 1331, 1369, 1458, 1536, 1681, 1701, 1715, 1792, 1849, 1875, 2048, 2187, 2197, 2209, 2401, 2560, 2809, 3072, 3125, 3481, 3584, 3645, 3721, 4096, 4374, 4375, 4489, 4802, 4913, 5041, 5103, 5120, 5329, 6241, 6250, 6561, 6859, 6889, 7168, 7203, 7921]

Wren

Library: Wren-math
Library: Wren-seq
Library: Wren-fmt
import "./math" for Int
import "./seq" for Lst
import "./fmt" for Fmt

var analyze = Fn.new { |n, b|
    var factors = Int.primeFactors(n)
    var indivs = Lst.individuals(factors)
    var digits = 0
    for (indiv in indivs) {
        digits = digits + Int.digits(indiv[0], b).count
        if (indiv[1] > 1) digits = digits + Int.digits(indiv[1], b).count
    }
    return [Int.digits(n, b).count, digits]
}

for (b in [10, 11]) {
    var w = []
    var e = [1]
    var f = []
    var wc = 0
    var ec = 1
    var fc = 0
    var wc2 = 0
    var ec2 = 1
    var fc2 = 0
    var n = 2
    System.print("FOR BASE %(b):\n")
    while (fc < 10000 || ec < 10000 || wc < 10000) {
        var r = analyze.call(n, b)
        if (r[0] < r[1]) {
            if (w.count < 50 || wc == 9999) w.add(n)
            wc = wc + 1
            if (n < 1e6) wc2 = wc2 + 1
        } else if (r[0] == r[1]) {
            if (e.count < 50 || ec == 9999) e.add(n)
            ec = ec + 1
            if (n < 1e6) ec2 = ec2 + 1
        } else {
            if (f.count < 50 || fc == 9999) f.add(n)
            fc = fc + 1
            if (n < 1e6) fc2 = fc2 + 1
        }
        n = n + 1
    }
    System.print("First 50 Wasteful numbers:")
    Fmt.tprint("$4d", w[0..49], 10)
    System.print()
    System.print("First 50 Equidigital numbers:")
    Fmt.tprint("$4d", e[0..49], 10)
    System.print()
    System.print("First 50 Frugal numbers:")
    Fmt.tprint("$4d", f[0..49], 10)
    System.print()
    System.print("10,000th Wasteful number    : %(w[50])")
    System.print("10,000th Equidigital number : %(e[50])")
    System.print("10,000th Frugal number      : %(f[50])")
    System.print()
    System.print("For natural numbers < 1 million, the breakdown is as follows:")
    Fmt.print("  Wasteful numbers    : $6d", wc2)
    Fmt.print("  Equidigital numbers : $6d", ec2)
    Fmt.print("  Frugal numbers      : $6d", fc2)
    System.print()
}
Output:
FOR BASE 10:

First 50 Wasteful numbers:
   4    6    8    9   12   18   20   22   24   26 
  28   30   33   34   36   38   39   40   42   44 
  45   46   48   50   51   52   54   55   56   57 
  58   60   62   63   65   66   68   69   70   72 
  74   75   76   77   78   80   82   84   85   86 

First 50 Equidigital numbers:
   1    2    3    5    7   10   11   13   14   15 
  16   17   19   21   23   25   27   29   31   32 
  35   37   41   43   47   49   53   59   61   64 
  67   71   73   79   81   83   89   97  101  103 
 105  106  107  109  111  112  113  115  118  119 

First 50 Frugal numbers:
 125  128  243  256  343  512  625  729 1024 1029 
1215 1250 1280 1331 1369 1458 1536 1681 1701 1715 
1792 1849 1875 2048 2187 2197 2209 2401 2560 2809 
3125 3481 3584 3645 3721 4096 4374 4375 4489 4802 
4913 5041 5103 5329 6241 6250 6561 6859 6889 7203 

10,000th Wasteful number    : 14346
10,000th Equidigital number : 33769
10,000th Frugal number      : 1953125

For natural numbers < 1 million, the breakdown is as follows:
  Wasteful numbers    : 831231
  Equidigital numbers : 165645
  Frugal numbers      :   3123

FOR BASE 11:

First 50 Wasteful numbers:
   4    6    8    9   10   12   18   20   22   24 
  26   28   30   33   34   36   38   39   40   42 
  44   45   46   48   50   51   52   54   55   56 
  57   58   60   62   63   65   66   68   69   70 
  72   74   75   76   77   78   80   82   84   85 

First 50 Equidigital numbers:
   1    2    3    5    7   11   13   14   15   16 
  17   19   21   23   25   27   29   31   32   35 
  37   41   43   47   49   53   59   61   64   67 
  71   73   79   81   83   89   97  101  103  107 
 109  113  121  122  123  127  129  131  133  134 

First 50 Frugal numbers:
 125  128  243  256  343  512  625  729 1024 1331 
1369 1458 1536 1681 1701 1715 1792 1849 1875 2048 
2187 2197 2209 2401 2560 2809 3072 3125 3481 3584 
3645 3721 4096 4374 4375 4489 4802 4913 5041 5103 
5120 5329 6241 6250 6561 6859 6889 7168 7203 7921 

10,000th Wasteful number    : 12890
10,000th Equidigital number : 33203
10,000th Frugal number      : 2659171

For natural numbers < 1 million, the breakdown is as follows:
  Wasteful numbers    : 795861
  Equidigital numbers : 200710
  Frugal numbers      :   3428