-COMPLETE- Code Challenge #7: Pangram checker
Update, October 2, 2025: A HUGE thanks to everyone who participated in this challenge! The correct answer is: 819 Non-Pangrams, 132 Pangrams (non-perfect) and 49 Perfect-Pangrams. We are very impressed by the variety of approaches and languages used in this exercise.
The exercise was successfully completed by 86 out of 95 entries (91%).
Congratulations to the following users for successfully solving the challenge: lyxal, depperm, jirassimok, Lukasz Szozda, KIKO Software, jared_mamrot, chrslg, Sep Roland, dani-vta, Amadan, sehe, R T, YungDeiza, Wilson, Xirtaminu, Faraaz Kurawle, Kenzo Staelens, Nevpzo, Echsecutor, Kamran, ls91, samkart, JoaoFCarvalho, Themoonisacheese, Utopia, Narek Torosyan, The_spider, Schnitte, Jim, DarkTheme, Satarupa, Rawson, Markus, Vampire, Christos Polimatidis, MaxCodes, snoski, Ka'Eios, Kickerflix, George V, Chris Athanasiadis, Max Valentine, Naeio, Hmwat, 啊鹿Dizzyi, llane12, Alf Kåre Lefdal, Shankaragouda, Joan, JimN, Grismar, LukasKroess, Thom omega, Colin Emonds, Sujay_ks, choroba, Booboo, Aren, mdyousufniaz, Ben, Mstar, BrownHat, DBambino, Ssword, Jean-Francois T., user31577179, Hitarth Doctor, Marc Lambrichs, Daniel, Stefan Reisner, Jérôme Migné, Code_cubes, gee3107, Harshank Bansal, Andam, Dwayne Robinson, Jean-Francois T., Christian, Shivam, Remy, gimix, André, rizesky, Twineee The Zelda Wizard, Übermensch, Abhay Kumar Yadav
Original Post
Today we have a new format for our challenge, we call it a pass/fail style. This means that everyone who completes the prompt and gets the right answer will be recognized! You can still vote on the entries, but we won’t be judging based on the votes.
The Challenge
In this challenge we are looking some special categories of text strings: pangrams and perfect pangrams.
Pangrams are phrases which contain every letter of the English alphabet at least once. For example "The quick brown fox jumps over a lazy dog.”
Perfect pangrams contain each letter of the English alphabet exactly once. For example “Mr Jock, TV quiz PhD, bags few lynx.”
For the challenge, create a program that takes a list of strings and determines the count of non-pangrams, pangrams and perfect pangrams. Tell us the count of each of these in this list of 1000 strings.
Key dates:
You have two weeks from the date this challenge is posted to submit your entry.
September 17: Challenge goes live
October 1: Deadline for submitting challenge entries for recognition. Winners will be announced on this date or soon after.
How to Submit
Enter your submission in the text box below.
Your submission should include:
The count of non-pangrams, pangrams and perfect pangrams in the provided file
The code you have written
[Optional] Anything you learned or any interesting challenges you faced while coding
Your entry is not permitted to be written by AI. For any feedback on this Challenge, please head over to the Meta post.
Oldest first — sorts entries by their creation dates, with the oldest at the top.
Newest first — sorts entries by their creation dates, with the newest at the top.
Latest activity — sorts entries with recent threaded replies or edits at the top.
Highest score — sorts entries by their total votes (highest first).
Your sorting method preferences will be saved.
- 435
- 4
- 9
Sry didnt see challenge until today, maybe next time.
#!/usr/bin/perl -w
use JSON::XS; #to parse json file
undef $/; #grab entire json file at once
while(<>){
my $decodedJsonFile = decode_json($_);
my (@perfectPangram, @nonPerfectPangram, @nonPangram);
for $s (@{$decodedJsonFile}){
if(&checkPangram($s) == 0){
push(@nonPangram, $s);
}else{
(&checkPerfectPangram($s) == 0) ? push(@nonPerfectPangram, $s) : push(@perfectPangram, $s);
}
}
print "Perfect " . @perfectPangram . "\n";
print "Non-Perfect " . @nonPerfectPangram . "\n";
print "Non-Pangram " . @nonPangram . "\n";
}
sub checkPangram{
my %charCount;
#put each char in hash
for( split('',$_[0]) ){
$charCount{lc($_)}++;
}
for( 'a' .. 'z'){
return 0 if(!defined($charCount{$_}));
}
return 1;
}
sub checkPerfectPangram{
my %charCount;
#put each char in hash
for( split('',$_[0]) ){
$charCount{lc($_)}++;
}
for( 'a' .. 'z'){
return 0 if($charCount{$_} != 1);
}
return 1;
}
Output:
$ perl pangram.pl pangram.json
Perfect 49
Non-Perfect 132
Non-Pangram 819
- 1.8k
- 8
- 18
Sad I missed this challenge. Only just saw it today.
Python - one liner using list comprehension, walrus operator, and pd.Series.value_counts()
import numpy as np, pandas as pd, re
words = 'List of 1000 strings.json'
pd.Series(['perfect panagram' if (max(letters:=(pd.Series(list(re.sub('[^a-z]', '', x.lower()))).value_counts()))==1 and len(letters)==26) else ('panagram' if len(letters)==26 else 'non-panagram') for x in words]).value_counts()
non-panagram 819
panagram 132
perfect panagram 49
Name: count, dtype: int64
'letters' (using walrus operator) returns a pandas series of each letter (converted to lowercase and with non-letters removed) with a count for each letter.
the logic:
'perfect panagram' if the highest count (max) in the list of letter-counts is 1 AND the length of unique letters is 26 ELSE
'panagram' if the length of unique letters is 26 ELSE
'non-panagram'

- 1.9k
- 14
- 27
import json
input_file = 'list of 1000 strings.json'
pangrams = []
perfects = []
neither = []
all_letters = set(chr(c) for c in range(ord('a'), ord('z') + 1))
data = json.load(open(input_file, 'r'))
for string in data:
# Remove non-letter characters and convert to lowercase, count each letter
clean = ''.join(filter(str.isalpha, string.lower()))
counts = {char: clean.count(char) for char in all_letters}
# If all letters appear exactly once, it's a perfect pangram
if all(count == 1 for count in counts.values()):
perfects.append(string)
# If all letters still appear at least once, it's a pangram
elif all(count >= 1 for count in counts.values()):
pangrams.append(string)
# If neither, this is not a pangram
else:
neither.append(string)
print(f"Total pangrams found: {len(pangrams):3d}")
print(f"Total perfect pangrams found: {len(perfects):3d}")
print(f"Total non-pangrams found: {len(neither):3d}")
Output:
Total pangrams found: 132
Total perfect pangrams found: 49
Total non-pangrams found: 819
- 3.8k
- 2
- 8
- 27
import json
def pangrams(filename):
alphabet = set('abcdefghijklmnopqrstuvwxyz')
no_pangrams = 0
pangrams = 0
perf_pangrams = 0
content = json.load(open(filename, 'r'))
for line in content:
line = line.strip().lower()
if len(line) < 26 or not alphabet <= set(line): #cannot be a pangram
no_pangrams += 1
else: #is a pangram, check if perfect
visited = set()
for char in line:
if char in alphabet:
if char in visited:
pangrams += 1
break
visited.add(char)
else:
perf_pangrams += 1
return no_pangrams, pangrams, perf_pangrams
Returns: (819, 132, 49)

- 807
- 2
- 9
- 17
Answer
Non-pangrams: 819
Pangrams: 132
Perfect pangrams 49
Code
<?php
declare(strict_types=1);
$pathToFile = __DIR__ . DIRECTORY_SEPARATOR . 'List of 1000 strings.json';
$lines = json_decode(file_get_contents($pathToFile));
$alphabet = array_flip(range('a', 'z'));
$pangramCount = 0;
$perfectPangramCount = 0;
foreach ($lines as $line) {
$lineToLower = strtolower($line);
$charFrequency = array_intersect_key(
array_count_values(
str_split($lineToLower)
),
$alphabet
);
$isNonPangram = count($charFrequency) !== count($alphabet);
if ($isNonPangram) continue;
$isPerfectPangram = array_sum($charFrequency) === count($alphabet);
if ($isPerfectPangram) {
$perfectPangramCount++;
} else {
$pangramCount++;
}
}
$nonPangramCount = count($lines) - ($pangramCount + $perfectPangramCount);
echo sprintf('Non-pangrams: %s', $nonPangramCount) . PHP_EOL;
echo sprintf('Pangrams: %s', $pangramCount) . PHP_EOL;
echo sprintf('Perfect pangrams %s', $perfectPangramCount) . PHP_EOL;
exit(0);

- 49.1k
- 13
- 97
- 163
echo sprintf()
is an antipattern - it is never appropriate. This is what printf()
is for.
Python Solution - Pangram Checker
First I downloaded and saved the provided pangrams.json file in the same directory.
Here's the python code for categorizing the perfect pangrams, pangrams and non pangrams.
Python Code - Solution
# Pangram checker
import json
class Pangram:
def check(self, s:str):
count = 0
overall = 0
alphabet_dictionary = {'a':0, 'b':0, 'c':0, 'd':0, 'e':0, 'f':0, 'g':0, 'h':0, 'i':0, 'j':0, 'k':0, 'l':0, 'm':0, 'n':0, 'o':0, 'p':0, 'q':0, 'r':0, 's':0, 't':0, 'u':0, 'v':0, 'w':0, 'x':0, 'y':0, 'z':0}
for letter in s:
if letter in alphabet_dictionary.keys():
if alphabet_dictionary[letter] == 0:
count += 1
alphabet_dictionary[letter] += 1
overall += 1
if count == 26 and overall == 26:
return 1
if count == 26:
return 0
if count != 26:
return -1
return -2
def main(self):
# Pangram object
P = Pangram()
# read list of strings
with open("pangrams.json", "r", encoding="utf-8") as file:
L = json.load(file)
file.close()
nonPangrams = 0
pangrams = 0
perfectPangrams = 0
for line in L:
result = P.check(line.lower())
if result == 1:
perfectPangrams += 1
elif result == 0:
pangrams += 1
elif result == -1:
nonPangrams += 1
else:
print("There's some error in logic.")
print("Perfect Pangrams:", perfectPangrams)
print("Pangrams:", pangrams)
print("Non Pangrams:", nonPangrams)
if __name__ == "__main__":
P = Pangram()
P.main()
Result
Perfect Pangrams: 49
Pangrams: 132
Non Pangrams: 819
The program effectively calculated the pangrams.
- 1.6k
- 2
- 13
- 16
Counts:
'no pangram': 819
'pangram': 132
'perfect pangram': 49
Code:
words = [
"Bright vixens jump; dozy fowl quack.",
...
]
from collections import Counter
ordA = ord('a')
ordZ = ord('z')
def calcLetterCount(word: str):
counts = {chr(a): 0 for a in range(ordA, ordZ + 1)}
for c in word.lower():
if ordA <= ord(c) and ord(c) <= ordZ:
counts[c] += 1
return counts
def pangramState(word: str):
letterCounts = calcLetterCount(word)
perfectPangram = True
for count in letterCounts.values():
if count == 0:
return "no pangram"
if count > 1:
perfectPangram = False
if perfectPangram:
return "perfect pangram"
return "pangram"
pangramCounter = Counter(pangramState(w) for w in words)
- 13.2k
- 7
- 81
- 117
Language: Swan
Type | Count |
---|---|
Non-pangrams | 819 |
Imperfect pangrams | 132 |
Perfect pangrams | 49 |
Implementation with Graphical operators
The implementation is using graphical diagram using Scade One tool from Ansys (part of Synopsys).
The algorithm is using a bitmask to detect whether a letter (lowercase or uppercase) has been found; for example, the number 13
(i.e. 0...01101
) means that we have found letters a
, c
, and d
.
The types of pangrams are declared as an enum type for more convenience.
As images cannot be added, here are some links of the implemented operators (stored in Github):
See the following Gist for more convenience.
Here is the swan file corresponding to these implementations:
-- version swan: 2025.2 graph: 2.1
use charUtils;
function GetPangramType (sentence: char^STR_LENGTH;)
returns (pangram_type: PangramType;)
{
diagram
(#0 expr forward
<<STR_LENGTH>> with [c]=sentence;
diagram
(#1 def asciiCode
#pragma diagram {"xy":"h34450;v-29600","wh":"14000;3200"} #end)
(#2 expr charUtils::char2uint32(c)
#pragma diagram {"xy":"h-14060;v-29600","wh":"28000;3200"} #end)
(#3 wire #2 => #1)
(var
asciiCode;)
(activate #5
if (65 <= asciiCode) and (asciiCode <= 90)
then
{
diagram
(#6 expr last'maskOccurence lor (1 lsl (asciiCode - 65))
#pragma diagram {"xy":"h-6625;v-5076","wh":"50000;3200"} #end)
(#7 def maskOccurence
#pragma diagram {"xy":"h36450;v-5076","wh":"18000;3200"} #end)
(#8 expr last'multipleOccurences
#pragma diagram {"xy":"h-12450;v1276","wh":"26000;3200"} #end)
(#9 expr (last'maskOccurence land (1 lsl (asciiCode - 65))) > 0
#pragma diagram {"xy":"h-27000;v5076","wh":"56000;3200"} #end)
(#10 expr #11 or #12
where
(#11 group)
(#12 group)
#pragma diagram {"xy":"h14000;v3176"} #end)
(#13 def multipleOccurences
#pragma diagram {"xy":"h38450;v3176","wh":"22000;3200"} #end)
(#14 wire #6 => #7)
(#15 wire #9 => #12)
(#16 wire #8 => #11)
(#17 wire #10 => #13)
#pragma diagram {"xy":"h0;v-13778","wh":"114000;17352"} #end
}
elsif (97 <= asciiCode) and (asciiCode <= 122)
then
{
diagram
(#18 expr last'maskOccurence lor (1 lsl (asciiCode - 97))
#pragma diagram {"xy":"h-7950;v-5049","wh":"50000;3200"} #end)
(#19 def maskOccurence
#pragma diagram {"xy":"h36450;v-5049","wh":"18000;3200"} #end)
(#21 expr last'multipleOccurences
#pragma diagram {"xy":"h-12000;v1249","wh":"26000;3200"} #end)
(#22 def multipleOccurences
#pragma diagram {"xy":"h38450;v3149","wh":"22000;3200"} #end)
(#23 expr #24 or #25
where
(#24 group)
(#25 group)
#pragma diagram {"xy":"h14000;v3149"} #end)
(#26 expr (last'maskOccurence land (1 lsl (asciiCode - 97))) > 0
#pragma diagram {"xy":"h-27000;v5049","wh":"56000;3200"} #end)
(#20 wire #18 => #19)
(#27 wire #23 => #22)
(#28 wire #26 => #25)
(#29 wire #21 => #24)
#pragma diagram {"xy":"h0;v7406","wh":"114000;17297"} #end
}
else
{
#pragma diagram {"xy":"h0;v23114","wh":"114000;6400"} #end
}
#pragma diagram {"xy":"h0;v2205","wh":"114000;52628"} #end)
until asciiCode = 0
returns (maskOccurence: last=0_ui32,
multipleOccurences: last=false)
#pragma diagram {"xy":"H-53452;V20029","wh":"122600;78399"} #end)
(/* ASCII TABLE
A = 65 .. Z = 90
a = 97 .. z = 122
To recorde the occurence of letters,
we use a bitmask for the position of the letter in the alphabet
(starting by 0).
If the bitmask = 67108863 (2^26-1), then all letters have been found.
We will also need to record if a letter has been found twice,
by using the bitmask to check whether we have a previous occurence.
*/ let
#pragma diagram {"xy":"H-38588;V-54226","wh":"70000;22814"} #end)
(#30 def pangram_type
#pragma diagram {"xy":"H81748;V65128","wh":"16000;3200"} #end)
(#31 expr NOT_PANGRAM
#pragma diagram {"xy":"H31748;V68828","wh":"16000;3200"} #end)
(#32 expr if #33 then #34 else #35
where
(#33 group)
(#34 group)
(#35 group)
#pragma diagram {"xy":"H56748;V65128"} #end)
(#36 expr 67108863
#pragma diagram {"xy":"H18798;V42228","wh":"12000;3200"} #end)
(#37 expr #38 = #39
where
(#38 group)
(#39 group)
#pragma diagram {"xy":"H34748;V44128"} #end)
(#40 expr PANGRAM
#pragma diagram {"xy":"H1848;V61328","wh":"12000;3200"} #end)
(#41 expr if #42 then #43 else #44
where
(#42 group)
(#43 group)
(#44 group)
#pragma diagram {"xy":"H34748;V63228"} #end)
(#45 expr PERFECT_PANGRAM
#pragma diagram {"xy":"H-2152;V65128","wh":"20000;3200"} #end)
(#46 wire #31 => #35
#pragma diagram {"wp":"#31 h7500 v-1800 #35"} #end)
(#47 wire #0 .(2) => #39
#pragma diagram {"wp":"v25999|#0 #39"} #end)
(#48 wire #36 => #38)
(#49 wire #37 => #33
#pragma diagram {"wp":"#37 h18500 #33"} #end)
(#50 wire #0 .(3) => #42
#pragma diagram {"wp":"v36949|#0 h26900 #42"} #end)
(#51 wire #40 => #43)
(#52 wire #45 => #44)
(#53 wire #41 => #34)
(#54 wire #32 => #30)
}
function CountPangrams <<N>> (listStrings: char^STR_LENGTH^N;)
returns (countNonPangrams: uint32;
countPangrams: uint32;
countPerfectPangrams: uint32;)
{
diagram
(#0 expr forward
<<N>> with [s]=listStrings;
diagram
(activate #1 when GetPangramType(s) match
| NOT_PANGRAM :
{
diagram
(#2 def nbNonP
#pragma diagram {"xy":"h15000;v0","wh":"10000;3200"} #end)
(#3 expr last'nbNonP + 1
#pragma diagram {"xy":"h-12000;v0","wh":"20000;3200"} #end)
(#4 wire #3 => #2)
#pragma diagram {"xy":"h0;v-7700","wh":"52000;7200"} #end
}
| PANGRAM :
{
diagram
(#5 def nbPangram
#pragma diagram {"xy":"h17000;v0","wh":"14000;3200"} #end)
(#6 expr last'nbPangram + 1
#pragma diagram {"xy":"h-13000;v0","wh":"22000;3200"} #end)
(#7 wire #6 => #5)
#pragma diagram {"xy":"h0;v3359","wh":"52000;7200"} #end
}
| PERFECT_PANGRAM :
{
diagram
(#8 def nbPerfectP
#pragma diagram {"xy":"h17000;v0","wh":"14000;3200"} #end)
(#9 expr last'nbPerfectP + 1
#pragma diagram {"xy":"h-13000;v0","wh":"22000;3200"} #end)
(#10 wire #9 => #8)
#pragma diagram {"xy":"h0;v14419","wh":"52000;7200"} #end
}
#pragma diagram {"xy":"h-3025;v-1000","wh":"52000;36038"} #end)
returns (nbNonP: last=0_ui32,
nbPangram: last=0_ui32,
nbPerfectP: last=0_ui32)
#pragma diagram {"xy":"H-18350;V-17991","wh":"68650;54038"} #end)
(#11 def countNonPangrams
#pragma diagram {"xy":"H43925;V-26691","wh":"20000;3200"} #end)
(#12 def countPangrams
#pragma diagram {"xy":"H42925;V-15631","wh":"18000;3200"} #end)
(#13 def countPerfectPangrams
#pragma diagram {"xy":"H45925;V-4572","wh":"24000;3200"} #end)
(#14 wire #0 .(1) => #11
#pragma diagram {"wp":"v-8700|#0 #11"} #end)
(#15 wire #0 .(2) => #12
#pragma diagram {"wp":"v2360|#0 #12"} #end)
(#16 wire #0 .(3) => #13
#pragma diagram {"wp":"v13419|#0 #13"} #end)
}
type PangramType = enum { NOT_PANGRAM, PANGRAM, PERFECT_PANGRAM };
const STR_LENGTH: int32 = 64;

- 4.2k
- 4
- 30
- 37
Wow, this one was exotic! Interesting language. Kind of neat to able to generate gate logic graphs from the code.

- 2.6k
- 1
- 31
- 44
Results
- Non-pangram count: 819
- Imperfect pangram count: 132
- Perfect pangram count: 49
- Total pangram count: 181 (perfect + imperfect)
Code
#include <iostream>
#include <fstream>
#include <print>
#include <chrono>
#include <algorithm>
#include <string>
#include <cassert>
const char* defaultFileName = "List of 1000 strings.json";
enum class PangramType
{
NotAPangram,
ImperfectPangram,
PerfectPangram,
};
char const* PangramTypeNames[3] = {"Not a pangram", "Pangram", "Perfect pangram"};
std::string ReadTextFile(const char* fileName);
std::string ReadTextFile(std::basic_istream<char, std::char_traits<char>>& inputStream);
std::string_view GetNextString(std::string_view text);
PangramType DeterminePangramType(std::string_view text);
int main()
{
int pangramCounts[3 /*PangramType total*/] = {};
std::string fileText = ReadTextFile(defaultFileName);
std::string_view fileTextRange = fileText;
auto fileTextRangeEnd = fileTextRange.data() + fileTextRange.size(); // Can't use end() because of debug iterator bogus warning.
while (true)
{
std::string_view stringRange = GetNextString(fileTextRange);
if (stringRange.empty())
break;
PangramType pangramType = DeterminePangramType(stringRange);
++pangramCounts[size_t(pangramType)];
std::println("{} - {}", stringRange, PangramTypeNames[size_t(pangramType)]);
auto stringRangeEnd = stringRange.data() + stringRange.size() + 1;
fileTextRange = std::string_view{stringRangeEnd, fileTextRangeEnd};
}
std::println();
std::println("Non-pangram count: {}", pangramCounts[size_t(PangramType::NotAPangram)]);
std::println("Imperfect pangram count: {}", pangramCounts[size_t(PangramType::ImperfectPangram)]);
std::println("Perfect pangram count: {}", pangramCounts[size_t(PangramType::PerfectPangram)]);
std::println("Total pangram count: {} (perfect + imperfect)", pangramCounts[size_t(PangramType::ImperfectPangram)] + pangramCounts[size_t(PangramType::PerfectPangram)]);
return EXIT_SUCCESS;
}
std::string_view GetNextString(std::string_view text)
{
auto startPosition = text.find('"');
if (startPosition == std::string::npos)
return {};
auto endPosition = text.find('"', startPosition + 1);
if (endPosition == std::string::npos)
return {};
auto range = std::string_view(text).substr(startPosition + 1, endPosition - startPosition - 1);
return range;
}
std::string ReadTextFile(std::basic_istream<char, std::char_traits<char>>& inputStream)
{
std::string dataBuffer;
// Avoid unnecessary zeroing of the buffer which will just be overwritten anyway.
// The transient indeterminate values between resize_and_overwrite and read are irrelevant.
inputStream.seekg(0, std::ios_base::end);
std::size_t fileSize = inputStream.tellg();
inputStream.seekg(0, std::ios_base::beg);
auto dummyResize = [](char* buffer, std::size_t fileSize) noexcept -> size_t { return fileSize;};
dataBuffer.resize_and_overwrite(fileSize, dummyResize);
inputStream.read(dataBuffer.data(), fileSize);
return dataBuffer;
}
std::string ReadTextFile(const char* fileName)
{
std::ifstream inputStream(fileName, std::ios::binary);
if (!inputStream.is_open())
{
std::cerr << "Could not open the file - '" << fileName << "'" << std::endl;
return {};
}
std::string dataBuffer = ReadTextFile(inputStream);
inputStream.close();
return dataBuffer;
}
PangramType DeterminePangramType(std::string_view text)
{
bool lettersSeen[26] = {};
int letterCount = 0;
int uniqueLetterCount = 0;
for (char c : text)
{
c &= ~0x20; // Convert to uppercase.
if (c >= 'A' && c <= 'Z')
{
++letterCount;
int letterIndex = c - 'A';
uniqueLetterCount += !lettersSeen[letterIndex];
lettersSeen[letterIndex] = true;
}
}
if (uniqueLetterCount < sizeof(lettersSeen))
{
return PangramType::NotAPangram;
}
else if (letterCount == sizeof(lettersSeen))
{
return PangramType::PerfectPangram;
}
else
{
return PangramType::ImperfectPangram;
}
}

- 2.2k
- 1
- 10
- 28
The list contains 49 Perfect, 132 that has duplicates but also all the letter of English alphabet and 819 that are missing one or more letters of English alphabet.
Below code will produce above stats and some more details for fun such as the missing letters the failed cases.
function cleanString(textToBeCleaned) {
return textToBeCleaned.replace(/[^a-zA-Z]/g, '').toLowerCase()
}
function check(listOfText) {
const alphabet = "abcdefghijklmnopqrstuvwxyz";
var result = {
Perfect: { count: 0, details: [] },
Partial: { count: 0, details: [] },
Failed: { count: 0, details: [] },
timeStampStart: 0,
timeStampEnd: 0,
durationMs: 0
};
result.timeStampStart = Date.now();
for (var i = 0; i < listOfText.length; i++) {
const cleanedText = cleanString(listOfText[i]);
const unique = new Set(cleanedText);
if (unique.size === 26 && cleanedText.length === 26) {
result.Perfect.count++;
result.Perfect.details.push({ text: listOfText[i] });
} else if (unique.size === 26 && cleanedText.length > 26) {
result.Partial.count++;
result.Partial.details.push({ text: listOfText[i] });
} else {
result.Failed.count++;
const missing = alphabet.split('').filter(ch => !unique.has(ch)).join();
result.Failed.details.push({ text: listOfText[i], missing });
}
}
result.timeStampEnd = Date.now();
result.durationMs = result.timeStampEnd - result.timeStampStart;
return result;
}
console.log(check(data)); // data is an array with all your strings in it such as the list provided in the challenge

- 3.4k
- 2
- 11
- 30
Output
Number of non pangrams: 819
Number of pangrams: 181
Number of pure pangrams: 49
Code Logic
- Use regex to remove non alphabets
- Create set of these letters, it will give unique alphabets in a line
- if the length of unique alphabets == 26 it is pangram
- if it is pangram and the length of output of step1 is also 26, then it is pure
Code
from pathlib import Path
import re
import json
if __name__ == "__main__":
data_file = Path(__file__).parent / "pangram.json"
with open(data_file, "r") as f:
lines = json.loads(f.read())
everything_else_then_lowercase_regex = re.compile(r"[^a-z]")
pangram_count = 0
pure_pangram_count = 0
for s in lines:
only_alphabets = re.sub(everything_else_then_lowercase_regex, "", s.lower())
unique_alphabets = set(only_alphabets)
is_pangram = len(unique_alphabets) == 26
is_pure = is_pangram and (len(only_alphabets) == 26)
pangram_count += is_pangram
pure_pangram_count += is_pure
print("Number of non pangrams:", len(lines) - pangram_count)
print("Number of pangrams:", pangram_count)
print("Number of pure pangrams:", pure_pangram_count)
Not Pangram: 431 Non-Perfect Pangram: 522 Perfect Pangram: 49
currentLetters = []
currentType = 0
canBePerfect = True
notPangram = 0
pangram = 0
perfectPangram = 0
bannedPatterns = [";",",","\n"," ",'"',"!","?","'",".","-"]
with open('List of 1000 strings.json') as file:
for line in file:
for pattern in bannedPatterns:
line = line.replace(pattern,"")
line = line.lower()
if len(line) > 25:
for letter in line:
if letter not in currentLetters:
currentLetters.append(letter)
elif letter in currentLetters:
canBePerfect = False
if len(currentLetters) > 25 & canBePerfect == True:
perfectPangram += 1
elif len(currentLetters) > 25 & canBePerfect == False:
pangram += 1
else:
notPangram += 1
currentLetters = []
canBePerfect = True
else:
notPangram += 1
print(f"Not Pangram: {notPangram}\n"
f"Non-Perfect Pangram: {pangram}\n"
f"Perfect Pangram: {perfectPangram}\n")
Turns out I forgot to account for something, I still don't know what it is but after seeing other people's answers, I know I'm not correct.

- 101
- 4
Thanks for your submission. I think something is off with the logic. I'll try to take a look later on.
- 7.1k
- 5
- 46
- 53
I think you just need to use and
instead of &
- see what is the difference between "&" and "and" in Python?
@peter-hull Thanks so much, turns out I actually am learning something from this challenge!
- 362
- 3
- 15
There are 819 non-pangrams, 132 pangrams and 49 perfect pangrams in the list given.
I coded my solution using Python 3.13.7, no external librairies needed.
My code is accessible at https://github.com/genevieve-le-houx/SO_challenge_7_pangram_checker
Here is my code:
import json
from typing import List, Dict
NUMBER_OF_LETTERS = 26
def read_sentence(filename: str) -> List[str]:
with open(filename, "r") as file:
data = json.load(file)
return data
def find_category(sentence: str) -> str:
all_letters = [x for x in sentence.lower() if x.isalpha()]
all_unique_letters = set(all_letters)
if len(all_unique_letters) == NUMBER_OF_LETTERS:
if len(all_letters) > NUMBER_OF_LETTERS:
category = "pangrams"
else:
category = "perfect pangrams"
else:
category = "non-pangrams"
return category
def count_pangram(sentences: List[str]) -> Dict[str, int]:
dict_count = {
"non-pangrams": 0,
"pangrams": 0,
"perfect pangrams": 0,
}
for sentence in sentences:
dict_count[find_category(sentence)] += 1
return dict_count
def main():
sentences = read_sentence("List of 1000 strings.json")
dict_count = count_pangram(sentences)
# Optional verification
if len(sentences) != sum(dict_count.values()):
print("The total of count doesn't match the number of sentenctes.")
print(dict_count)
if __name__ == '__main__':
main()
This reply has been deleted.

- 101
- 4
Thanks for attempting the challenge. This isn't the correct answer. If I get time, I'll try to look at your logic.
import string
def classify_strings(strings):
alphabet = set(string.ascii_lowercase)
counts = {"non_pangram": 0, "pangram": 0, "perfect_pangram": 0}
for s in strings:
# normalize: lowercase, keep only letters
letters = [ch for ch in s.lower() if ch.isalpha()]
unique_letters = set(letters)
if unique_letters >= alphabet: # has all 26 letters
if len(letters) == 26 and unique_letters == alphabet:
counts["perfect_pangram"] += 1
else:
counts["pangram"] += 1
else:
counts["non_pangram"] += 1
return counts
# Example usage (replace with your 1000 strings list):
strings = [
"The quick brown fox jumps over a lazy dog.",
"Mr Jock, TV quiz PhD, bags few lynx.",
"Hello World!",
]
result = classify_strings(strings)
print(result)
Originally solved in R, but having fun with visual languages so reimplemented in Snap!
non-pangram: 819
pangram: 132
perfect pangram: 49
Code (behind the scenes Lisp):
(
(receiveGo)
(set p_pangram
(list)
)
(set pangram
(list)
)
(set not_pangram
(list)
)
(forEach item
(get "List of 1000 strings") (
(set cand_form
(get item)
)
(ifElse
(>
(text [length]
(get cand_form)
) 25
) (
(set split_cand
(keep
(pred
(and
(< nil 123)
(< 96 nil)
)
)
(map
(ring
(unicode nil)
)
(split
(text "[lower case]"
(get cand_form)
) [letter]
)
)
)
)
(set og_abet_len
(data [length]
(get split_cand)
)
)
(ifElse
(>
(get og_abet_len) 25
) (
(set uniq_abet_len
(data [length]
(data [uniques]
(get split_cand)
)
)
)
(ifElse
(>
(get uniq_abet_len) 25
)
(ifElse
(=
(get og_abet_len)
(get uniq_abet_len)
)
(add
(get item)
(get p_pangram)
)
(add
(get item)
(get pangram)
)
)
(add
(get item)
(get not_pangram)
)
)
)
(add
(get item)
(get not_pangram)
)
)
)
(add
(get item)
(get not_pangram)
)
)
)
)
)
- 244
- 1
- 5
819, 181, 49
In the pangrams count (second number) I have included also the perfect pangrams (third number). Because "pangrams are phrases which contain every letter of the English alphabet at least once", so pangrams (without any adjective) includes both imperfect and perfect pangrams ("exactly once" is a subpart of "at least once").
use std::env;
use std::fs::File;
use std::io::BufReader;
fn main() {
let mut iter_args = env::args_os().skip(1);
if iter_args.len() != 1 {
eprintln!("Expected exactly 1 argument, the path of the input file.");
std::process::exit(1);
}
let input_path = iter_args.next().unwrap();
let file = File::open(input_path).expect("Error opening input file");
let reader = BufReader::new(file);
let strings: Vec<String> = serde_json::from_reader(reader).expect("Error reading json file");
let (non_pangrams, pangrams, perfect_pangrams) = get_pangram_counts(&strings);
println!("{non_pangrams}, {pangrams}, {perfect_pangrams}");
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum PangramCategory {
None,
Loose,
Perfect,
}
fn get_pangram_category(s: &str) -> PangramCategory {
let mut counts = [0_usize; (b'Z' - b'A') as usize + 1];
for mut byte in s.bytes() {
byte.make_ascii_uppercase();
if byte.is_ascii_uppercase() {
counts[(byte - b'A') as usize] += 1;
}
}
let mut category = PangramCategory::Perfect;
for cnt in counts {
if cnt == 0 {
return PangramCategory::None;
}
if cnt > 1 {
category = PangramCategory::Loose;
}
}
category
}
fn get_pangram_counts(strings: &Vec<String>) -> (usize, usize, usize) {
let (mut cnt_none, mut cnt_loose, mut cnt_perfect) = (0, 0, 0);
for s in strings {
match get_pangram_category(s) {
PangramCategory::None => cnt_none += 1,
PangramCategory::Loose => cnt_loose += 1,
PangramCategory::Perfect => cnt_perfect += 1,
}
}
(cnt_none, cnt_loose + cnt_perfect, cnt_perfect)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_pangram_category_empty() {
assert_eq!(get_pangram_category(""), PangramCategory::None);
}
#[test]
fn get_pangram_category_25() {
assert_eq!(
get_pangram_category("abcdefghijklmnopqrstuvwxy"),
PangramCategory::None
);
assert_eq!(
get_pangram_category("ABCDEFGHIJKLMNOPQRSTUVWXY"),
PangramCategory::None
);
}
#[test]
fn get_pangram_category_26() {
assert_eq!(
get_pangram_category("abcdefghijklmnopqrstuvwxyz"),
PangramCategory::Perfect
);
assert_eq!(
get_pangram_category("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
PangramCategory::Perfect
);
}
#[test]
fn get_pangram_category_27() {
assert_eq!(
get_pangram_category("abcdefghijklmnopqrstuvwxyzu"),
PangramCategory::Loose
);
assert_eq!(
get_pangram_category("ABCDEFGHIJKLMNOPQRSTUVWXYZU"),
PangramCategory::Loose
);
}
#[test]
fn get_pangram_category_none() {
assert_eq!(
get_pangram_category("a.b c,d;e?f-g hijklmno pqrstuvwxy"),
PangramCategory::None
);
assert_eq!(
get_pangram_category("The quick brown fox jumps over a dog."),
PangramCategory::None
);
}
#[test]
fn get_pangram_category_loose() {
assert_eq!(
get_pangram_category("a.b c,d;e?f-g hijklmno x pqrstuvwxyz"),
PangramCategory::Loose
);
assert_eq!(
get_pangram_category("The quick brown fox jumps over a lazy dog."),
PangramCategory::Loose
);
}
#[test]
fn get_pangram_category_perfect() {
assert_eq!(
get_pangram_category("a.b c,d;e?f-g hijklmno pqrstuvwxyz"),
PangramCategory::Perfect
);
assert_eq!(
get_pangram_category("Mr Jock, TV quiz PhD, bags few lynx."),
PangramCategory::Perfect
);
}
#[test]
fn get_pangram_counts_empty() {
let v = Vec::<String>::new();
assert_eq!(get_pangram_counts(&v), (0, 0, 0));
}
#[test]
fn get_pangram_counts_list() {
let strings = vec![
"".to_string(),
" ".to_string(),
"The quick brown fox jumps over a lazy dog.".to_string(),
"The quick brown fox jumps over a dog.".to_string(),
"Mr Jock, TV quiz PhD, bags few lynx.".to_string(),
"Mr Jack, TV quiz PhD, bogs few lynx.".to_string(),
"abcdefghijklmnopqrstuvwxy".to_string(),
"abcdefghijklmnopqrstuvwxyz".to_string(),
"abcdefghijklmnopqrstuvwxyza".to_string(),
];
assert_eq!(get_pangram_counts(&strings), (4, 5, 3));
}
}

- 705
- 6
- 14
My result is: {pangram=132, non-pangram=819, perfect pangram=49}
My code is:
package com.borrowbox.statistics
import java.io.File
import kotlinx.serialization.json.Json
fun main() {
try {
// Read JSON from file
val jsonString = File("List of 1000 strings.json").readText()
// Parse JSON to data class
val strings = Json.decodeFromString<List<String>>(jsonString)
val analysis = strings.map { analyze(it) }
val classifications = analysis.map { classify(it) }
val result = classifications.groupingBy { it }.eachCount()
println(result)
} catch (e: Exception) {
println("Error parsing JSON: ${e.message}")
}
}
fun classify(map: Map<Char, Int>): Classification =
if (map.size == 26) {
if (map.values.all { it == 1 }) Classification.PERFECT else Classification.PANGRAM
} else Classification.NOTHING
enum class Classification(val value: String) {
PANGRAM("pangram"),
PERFECT("perfect pangram"),
NOTHING("non-pangram");
override fun toString(): String = value
}
fun analyze(string: String): Map<Char, Int> {
val normalized = string.replace(Regex("[^a-zA-Z]"), "").uppercase()
return normalized.groupingBy { it }.eachCount()
}
My learning: I didn't know the eachCount() method before I did this challenge.

- 4.2k
- 4
- 30
- 37
*** Pangram checker report ***
Non-pangrams: 819
Pangrams: 132
Perfect pangrams: 49
package cli;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
public class Pangram {
private static void diagnoseOutput (boolean enable, String strFormat, Object... args) {
if (enable) {
System.out.printf(strFormat, args);
}
}
public static void main(String[] args) throws Exception {
List<String> lines = Files.readAllLines(Path.of("List of 1000 strings.json"));
boolean enableDiagnosingOutput = args.length > 0 && args[0].equals("--debug");
int perfectPangrams = 0;
int pangrams = 0;
int nonPangrams = 0;
for (int i = 1; i < lines.size() - 1; i++) {
int[] histogram = new int[26];
String orgLine = lines.get(i);
String line = orgLine.toUpperCase();
for (int j = 0; j < line.length(); j++) {
if (Character.isAlphabetic(line.charAt(j))) {
histogram[line.charAt(j) - 'A']++;
}
}
int numberOfOnes = 0;
int numberOfZeros = 0;
for (int k : histogram) {
if (k == 1) {
numberOfOnes++;
} else if (k == 0) {
numberOfZeros++;
}
}
if (numberOfOnes == 26) {
diagnoseOutput(enableDiagnosingOutput, "[%04d] %s is a PERFECT pangram!", i, orgLine);
perfectPangrams++;
} else if (numberOfZeros == 0) {
diagnoseOutput(enableDiagnosingOutput, "[%04d] %s is a pangram!", i, orgLine);
pangrams++;
} else {
diagnoseOutput(enableDiagnosingOutput, "[%04d] %s is NOT a pangram at all!", i, orgLine);
nonPangrams++;
}
diagnoseOutput(enableDiagnosingOutput,": %s%n", Arrays.toString(histogram));
}
System.out.println("*** Pangram checker report ***");
System.out.printf("Non-pangrams: %d%n", nonPangrams);
System.out.printf("Pangrams: %d%n", pangrams);
System.out.printf("Perfect pangrams: %d%n", perfectPangrams);
}
}
Optional: lesson learned, that there are numerous way of checking the results. For instance, any string less than 26 chars cannot be a pangram.

- 2.9k
- 2
- 15
- 16
Implementation in Elixir. For each string, we create a map with chars as key, and nr of occurrences as value. Then, for each map, check if it's perfect or not, or not even a pangram. While you're doing that, keep the count updated.
Solution will count perfect_pangrams separately, so a perfect pangram will not be counted as a pangram. Solution in ~ 13 ms.
iex(112)\> Challenges.PangramChecker.timer
{12933, %{pangram: 132, perfect_pangram: 49, non_pangram: 819}}
defmodule Challenges.PangramChecker do
@moduledoc """
Code Challenge #7: Pangram Checker
"""
def timer(), do: :timer.tc(__MODULE__, :solution, [])
def solution(file \\ "priv/files/List_of_1000_strings.json") do
# Read file
{:ok, list} = get_json(file)
# Translate capitals
Enum.map(list, fn str -> String.downcase(str) end)
# Globally replace non-letter chars
|> Enum.map(&Regex.replace(~r/[^a-z]/, &1, ""))
|> Enum.map(&String.to_charlist/1)
# Count characters
|> Enum.map(&count_chars(&1, Map.new()))
# Check of pangrams, perfect ones or non-pangrams
|> Enum.reduce(Map.new(), fn map, acc ->
cond do
is_perfect_pangram?(map) -> Map.update(acc, :perfect_pangram, 1, &(&1 + 1))
is_pangram?(map) -> Map.update(acc, :pangram, 1, &(&1 + 1))
true -> Map.update(acc, :non_pangram, 1, &(&1 + 1))
end
end)
end
defp get_json(filename) do
with {:ok, body} <- File.read(filename),
{:ok, json} <- Poison.decode(body) do
{:ok, json}
end
end
defp is_pangram?(map), do: Map.keys(map) |> Enum.count() == 26
defp is_perfect_pangram?(map) do
values = Map.values(map)
Enum.count(values) == 26 and Enum.sum(values) == 26
end
defp count_chars([], mem), do: mem
defp count_chars([x | xs], mem),
do: count_chars(xs, Map.update(mem, x, 1, &(&1 + 1)))
end
- 126
- 2
- 7
Panagram Type | Count |
---|---|
Non-Pangrams | 819 |
Pangrams | 132 |
Perfect Pangrams | 49 |
namespace Panagrams_stackoverflow
{
using System.IO;
using System.Collections;
using System.Text.Json;
public enum Panagram
{
Perfect = 1,
Panagram = 2,
Default = 0,
}
internal class Program
{
public const string ALPHA = "abcdefghijklmnopqrstuvwxyz";
public const int ALPHA_COUNT = 26;
public const int A_CHAR = (int)'a';
static void Main(string[] args)
{
var strings = GetStringsFromFile(Path.Combine(Directory.GetCurrentDirectory(), "Data/List of 1000 strings.json"));
int[] panagramCount = new int[3];
foreach (string @string in strings)
{
panagramCount[(int)CheckString(@string)]++;
}
///Test strings. ¯\_(ツ)_/¯
//panagramCount[(int)CheckString("Ttgrqeo cmlf xmtbaod lshsj xxhdst yslltct ute?")]++;
//panagramCount[(int)CheckString("Mr Jock, TV quiz PhD, bags few lynx.")]++;
//panagramCount[(int)CheckString("The quick brown fox jumps over a lazy dog.")]++;
Console.WriteLine($@"
{Panagram.Default.ToString()} {panagramCount[(int)Panagram.Default]}
{Panagram.Panagram.ToString()} {panagramCount[(int)Panagram.Panagram]}
{Panagram.Perfect.ToString()} {panagramCount[(int)Panagram.Perfect]}
");
}
static string[] GetStringsFromFile(string path)
{
if (File.Exists(path))
{
string jsonString = File.ReadAllText(path);
var strings = JsonSerializer.Deserialize<string[]> (jsonString);
return strings!;
}
return new string[0];
}
static Panagram CheckString (string text)
{
//Cannot be a panagram as text should include all letters.
if (text.Length < ALPHA_COUNT)
return Panagram.Default;
//Why bother with Lower and Upper case separately!?
text = text.ToLowerInvariant();
BitArray pending = new BitArray(26, true);
BitArray moreThanOne = new BitArray(26, false);
foreach (char letter in text)
{
if (char.IsLetter(letter))
{
int index = (int)letter - A_CHAR;
if (pending[index])
pending[index] = false;
else if(!moreThanOne[index])
{
moreThanOne[index] = true;
}
}
}
if (pending.HasAnySet())
return Panagram.Default;
if (moreThanOne.HasAnySet())
return Panagram.Panagram;
return Panagram.Perfect;
}
}
}
Had fun using BitArray after a while.
Non-Pangram: 819,
Pangram: 132,
Perfect Pangram: 49
let nonPangram=0, pangram = 0, perfectPangram = 0;
fetch("strings.json")
.then((response) => response.json())
.then((strings) => {
strings.forEach((string) => {
const chars = string.replace(/[^a-zA-Z0-9]/g, "").toUpperCase().split("");
if (chars.length <26) {
nonPangram++;
return;
}
else{
const countMap = {};
chars.forEach((char) => {
countMap[char] = (countMap[char] || 0) + 1;
});
const keyValueArray = Object.entries(countMap).map(([key, value]) => ({ key, value }));
if(keyValueArray.length < 26){
nonPangram++;
return;
}
else{
const allValuesAreOne = keyValueArray.every(item => item.value === 1);
if(allValuesAreOne){
perfectPangram++;
}
else{
pangram++;
}
}
}
});
document.getElementById("result").textContent = `Non-Pangram: ${nonPangram}, Pangram: ${pangram}, Perfect Pangram: ${perfectPangram}`;
console.log("Non-Pangram:", nonPangram);
console.log("Pangram:", pangram);
console.log("Perfect Pangram:", perfectPangram);
})
.catch((err) => console.error("Error loading JSON:", err));
- 13.2k
- 7
- 81
- 117
- Not Pangram: 819
- Pangram: 132
- Perfect Pangram: 49
I implemented in Python.
I used an enum to decribe the 3 different states and a Counter
(from the builtin library collections
) to count the occurrence of each letter. The list of letters can easily be obtained from string.ascii_lowercse
: we can easily compare the obtained letters and the required letters by a difference of set
:) ...
Tip: using a set
for the list of lower case letters will boost a bit the performance when checking if a character is among this list.
# %%
import enum
import string
from collections import Counter
class PangramCheck(enum.IntEnum):
"""An enumeration representing the status of a pangram check."""
NOT_PANGRAM = 0
PANGRAM = 1
PERFECT_PANGRAM = 2
# %%
def check_pangram(sentence: str) -> PangramCheck:
"""Check whether a sentence is a pangram"""
lower_case_letters = set(string.ascii_lowercase)
counts = Counter(c.lower() for c in sentence)
if lower_case_letters - set(counts):
return PangramCheck.NOT_PANGRAM
if any(c in lower_case_letters and i > 1 for c, i in counts.items()):
return PangramCheck.PANGRAM
return PangramCheck.PERFECT_PANGRAM
# if
lower_case_letters = set(string.ascii_lowercase)
sentence = "The quick brown fox jumps over a lazy dog."
sentence = "Mr Jock, TV quiz PhD, bags few lynx."
# sentence = "Hello You"
check_pangram(sentence)
# %%
list_of_1000_strings = [
"Bright vixens jump; dozy fowl quack.",
"zyra nymph, quid vex jock, fblg wt",
# ... truncated for keeping it concise
]
# %%
Counter(check_pangram(s) for s in list_of_1000_strings)
- 1
- 3
Here are the statistics of the sample file:
Statistics:
Number of Non Pangrams: 819
Number of Imperfect Pangrams: 132
Number of Perfect Pangrams: 49
Total Number of Pangrams: 181
Number of unique Imperfect Pangrams: 54
Number of unique Perfect Pangrams: 25
Total number of unique Pangrams: 79
Here is the code, to test this code, put a list-of-strings-to-pangram-test.json in the same directory as this file with the contents of the sample.
How this works:
Iterates through the characters in string, maintains a set of unused letters, when it encounters an alphabetical character, it does these 2 things:
If the character is in the set of unused letters, marks the character as used by removing the character in the set
If the character is not in the set of unused letters, marks the string as a possibly imperfect pangram (if it was a pangram in the first place)
Once reached the end of the string, it returns:
0 if not a pangram
1 if imperfect pangram
2 if perfect pangram
Then the rest of the code is for testing each string and printing statistics.
const STRINGS_TO_TEST = require("./list-of-strings-to-pangram-test.json");
// set of all uppercase alphabet letters.
const ALPHABET_LETTERS = new Set([
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
]);
// pangram function result enum
const NON_PANGRAM = 0;
const PANGRAM = 1;
const PERFECT_PANGRAM = 2;
// character codes. look this up at https://www.ascii-code.com/
const CC_A = 65;
const CC_Z = 90;
const CC_a = 97;
const CC_z = 122;
function is_alphabetical(c) {
const cc = c.charCodeAt(0);
return (CC_A <= cc && cc <= CC_Z) || (CC_a <= cc && cc <= CC_z);
}
/**
* @param {string} s
*
* TC - O(n)
* SC - O(1)
*/
function pangram(s) {
let perfect = true; // assume perfection
// initially have all letters as unused.
const unused_letters = new Set(ALPHABET_LETTERS);
// iterate through all characters of s.
for (const c of s) {
// ignore not alphabetical characters. this saves a bit of time
// and filters c to be alphabetical. this means i can use
// the uppercase version of c to check for usage without having
// false-positives.
if (!is_alphabetical(c)) {
continue;
}
// get the uppercase version of c. all the items
// in the set are upper case
// for case insensitivity.
const uc = c.toUpperCase();
// flag if is unused.
const is_unused = unused_letters.has(uc);
// if is unused, mark as used.
if (is_unused) {
unused_letters.delete(uc); // mark the letter as 'used'
}
// if is already used,
// then this is an imperfect pangram (characters are filtered
// as /[a-zA-Z]/).
// tl;dr: this character is used more than once.
else {
perfect = false; // mark as imperfect.
}
}
return unused_letters.size > 0 // there is remaining character, not pangram.
? NON_PANGRAM // not a pangram (there is unused character)
: perfect // the flag of perfection
? PERFECT_PANGRAM // used all character only once.
: PANGRAM; // is a pangram but used characters more than once.
}
// statistic variables.
let non_pangrams = 0;
let imperfect_pangrams = 0;
let unique_imperfect_pangrams = 0;
let perfect_pangrams = 0;
let unique_perfect_pangrams = 0;
let unique_pangram_map = new Map();
// iterate through each sample.
// the samples are defined to be this file
// https://drive.google.com/file/d/1nDVLzUkwbKwuPqZocVQnqkYFKwTu5mFQ/view?usp=sharing
for (const s of STRINGS_TO_TEST) {
const uc = s.toUpperCase();
if (unique_pangram_map.has(uc)) {
const type = unique_pangram_map.get(uc);
if (type === PERFECT_PANGRAM) {
perfect_pangrams++;
} else {
imperfect_pangrams++;
}
continue; // no use of testing what was already tested.
}
const type = pangram(s);
// bear with me, this might seem not DRY enough. but
// if it works, it works.
switch (type) {
case 0:
non_pangrams++;
break;
case 1:
imperfect_pangrams++;
unique_pangram_map.set(uc, 1);
unique_imperfect_pangrams++;
break;
case 2:
perfect_pangrams++;
unique_pangram_map.set(uc, 2);
unique_perfect_pangrams++;
break;
}
}
console.log(`Statistics: `);
console.log(`Number of Non Pangrams: ${non_pangrams}`);
console.log(`Number of Imperfect Pangrams: ${imperfect_pangrams}`);
console.log(`Number of Perfect Pangrams: ${perfect_pangrams}`);
console.log(
`Total Number of Pangrams: ${imperfect_pangrams + perfect_pangrams}`
);
console.log(
`Number of unique Imperfect Pangrams: ${unique_imperfect_pangrams}`
);
console.log(`Number of unique Perfect Pangrams: ${unique_perfect_pangrams}`);
console.log(
`Total number of unique Pangrams: ${
unique_imperfect_pangrams + unique_perfect_pangrams
}`
);
Pangrams: 132
Perfect Pangrams: 49
Non-Pangrams: 819
#include <iostream>
#include <algorithm>
#include <fstream>
void preprocess(std::string& line);
int main() {
// define variables
const std::string alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
const std::size_t Minimum = alphabet.size();
// Read phrases
int pangrams = 0, perfect = 0, other = 0;
std::ifstream phrases("phrases.txt", std::ifstream::in);
std::string line;
if (phrases.is_open()) {
while (getline(phrases, line)) {
preprocess(line);
const std::size_t size = line.size();
if (size < Minimum) {
other++;
} else if (size == Minimum) {
std::sort(line.begin(), line.end());
if (line == alphabet) {
perfect++;
} else {
other++;
}
} else {
std::sort(line.begin(), line.end());
auto it = std::unique(line.begin(), line.end());
line.resize(std::distance(line.begin(), it));
if (line == alphabet) {
pangrams++;
} else {
other++;
}
}
}
phrases.close();
}
std::cout << "Pangrams: " << pangrams << "\n";
std::cout << "Perfect Pangrams: " << perfect << "\n";
std::cout << "Non-Pangrams: " << other << "\n";
}
// Remove unneeded characters
void preprocess(std::string& line) {
line.erase(std::remove_if(line.begin(), line.end(), [](const char& c) { return !isalpha(c); }), line.end());
std::transform(line.begin(), line.end(), line.begin(), toupper);
}
C# Class for identifying Pangrams:
public class PangramChecker
{
/// <summary>
/// Determine if pangram is perfect.
/// </summary>
/// <param name="sourceString"></param>
/// <returns>
/// If returns null, string is not pangram.
/// If returns false, string is imperfect pangram.
/// If returns true, string is perfect pangram.
/// </returns>
public static bool? IsPerfectPangram(string sourceString)
{
var nonAlphaRegex = new Regex("[^a-zA-Z]");
sourceString = nonAlphaRegex.Replace(sourceString, "").ToLower();
if (string.IsNullOrEmpty(sourceString))
{
return null;
}
char currentChar;
int oldLength;
bool possiblePerfect = true;
List<char> foundChars = new List<char>();
do
{
oldLength = sourceString.Length;
currentChar = sourceString[0];
foundChars.Add(currentChar);
sourceString = sourceString.Replace(currentChar.ToString(), "");
possiblePerfect &= oldLength - sourceString.Length == 1;
} while (sourceString.Length > 0);
if (foundChars.Count == 26)
{
return possiblePerfect;
}
return null;
}
}
Running the Pangram Checker:
List<string> ReadStringsFromFileJson(string sourceFile)
{
if (!File.Exists(sourceFile))
{
Console.WriteLine("Source file not found.");
return new();
}
var jsonString = File.ReadAllText(sourceFile);
return JsonSerializer.Deserialize<List<string>>(jsonString) ?? new();
}
void RunPangramChecker()
{
string stringSourceFile = "List_of_1000_strings.json";
var sourceStrings = ReadStringsFromFileJson(stringSourceFile);
DateTime startTime, endTime;
int iteration = 0;
List<bool?> results = new();
startTime = DateTime.UtcNow;
foreach (var currentString in sourceStrings)
{
results.Add(PangramChecker.IsPerfectPangram(currentString));
}
endTime = DateTime.UtcNow;
Console.WriteLine($"# of non-pangrams: {results.Count(x => x == null)}");
Console.WriteLine($"# of imperfect pangrams: {results.Count(x => x == false)}");
Console.WriteLine($"# of perfect pangrams: {results.Count(x => x == true)}");
Console.WriteLine($"Processed {results.Count} strings in {(endTime - startTime).TotalSeconds} seconds.");
}
RunPangramChecker();
Results:
# of non-pangrams: 819
# of imperfect pangrams: 132
# of perfect pangrams: 49
Processed 1000 strings in 0.017415 seconds.
Another interesting challenge.

- 41.2k
- 10
- 49
- 90
I have chosen to parse the JSON file for an array of strings. (A simpler solution would have loaded the file whole and traversed the memory scanning for opening- and closing double quotation marks). The one thing my parser does not consider are escape sequences, but as it turns out none were used in the file. I think that including a few escape sequences could have made the task a bit more challenging!
The first thing my program does is setup a character translation table that will simplify and speedup the detection of whitespace and alphabetical characters as well as provide for case-insensitiveness.
For every string in the array a frequency table is created and if the sum of all 26 frequencies equals 26 while at the same time no frequency was found to be zero then it means that the string is a perfect pangram.
I'm running this 8086 (what fun!) program in the DOS 6.20 environment. The program was assembled with FASM.
C:\SO>1K Non-Pangram: 819, Pangram: 181, Perfect: 49 C:\SO>
; Challenge #7 --- Program to scan a list of strings
; and determine how many are (perfect) pangrams or not.
BUFSIZE equ 512
ORG 256 ; .COM program has CS=DS=ES=SS
INIT: sub sp, 26 ; FrequencyTable
mov bp, sp
cld
mov dx, TheFile
mov ax, 3D00h ; DOS.OpenFile for reading
int 21h ; -> AX CF
jc ABORT
mov [Handle], ax ; ReadPointer is kept in SI
xor dx, dx ; AvailableBytes is kept in DX
mov bx, Codes ; TranslationTable is kept in BX
; Parsing the JSON file for an array of strings
MAIN: call SkipWhitespace ; -> AL DX SI
cmp al, '[' ; Start of JSON array ?
jne ABORT
.STR: call SkipWhitespace ; -> AL DX SI
cmp al, 26 ; Start of JSON string ?
jne ABORT
mov di, bp ; Wipe table, resetting all
mov cx, 13 ; 26 byte-sized counters
xor ax, ax
rep stosw ; -> CX=0
.CHR: call GetOneByte ; -> AL DX SI
cmp al, 26 ; End of JSON string ?
ja .CHR ; Ignore non-alphabet in string
je .EOS
mov di, ax ; AX=[0,25]
mov al, [bp+di]
add al, 1 ; Count + 1
sbb al, 0 ; Saturating at 255
mov [bp+di], al
jmp .CHR
.EOS: mov di, 25 ; CX=0
@@: mov al, [bp+di] ; AH=0
cmp al, 0
je @f ; Early exit if not a pangram
add cx, ax ; CX becomes sum of all counters
dec di
jns @b
inc word [Pangram] ; It is a pangram, but
cmp cx, 26 ; CX is 26+ is it a perfect one?
ja @f
inc word [Perfect]
@@: inc word [Strings] ;Number of strings in the array
call SkipWhitespace ; -> AL DX SI
cmp al, ',' ; JSON element separator ?
je .STR ; Yes, go process another string
cmp al, ']' ; End of JSON array ?
jne ABORT
mov bx, [Handle]
mov ah, 3Eh ; DOS.CloseFile
int 21h ; -> AX CF
; Show results on the screen and terminate
mov dx, msgOK1
mov ah, 09h ; DOS.PrintString
int 21h ; -> AL='$'
mov ax, [Strings]
sub ax, [Pangram]
call ShowAX
mov dx, msgOK2
mov ah, 09h ; DOS.PrintString
int 21h ; -> AL='$'
mov ax, [Pangram]
call ShowAX
mov dx, msgOK3
mov ah, 09h ; DOS.PrintString
int 21h ; -> AL='$'
mov ax, [Perfect]
call ShowAX
mov dx, msgEOL
jmp EXIT
ABORT: mov dx, msgERR
EXIT: mov ah, 09h ; DOS.PrintString
int 21h ; -> AL='$'
mov ax, 4C00h ; DOS.TerminateWithExitcode
int 21h
; ------------------------------
; IN (bx,dx,si) OUT (al,dx,si)
SkipWhitespace:
call GetOneByte ; -> AL DX SI
cmp al, 32 ; One of {9,10,13,32}
je SkipWhitespace
ret
; ------------------------------
; Does not return if a file error occured
; IN (bx,dx,si) OUT (al,dx,si)
GetOneByte:
dec dx ; AvailableBytes - 1
js .LOAD
.FETCH: lodsb
xlatb
ret
.LOAD: push ax bx cx
mov si, Buffer ; Reset readpointer
mov dx, si
mov cx, BUFSIZE
mov bx, [Handle]
mov ah, 3Fh ; DOS.ReadFile
int 21h ; -> AX CF
mov dx, ax ; Available bytes
pop cx bx ax
jc ABORT
dec dx ; [0,BUFSIZE] -> [-1,BUFSIZE-1]
jns .FETCH
jmp ABORT
; ------------------------------
; Prints the unsigned word in AX with a prepended space character
; IN (ax) OUT ()
ShowAX: push ax bx cx dx
mov bx, sp
sub sp, 8
dec bx
mov byte [bx], '$'
mov cx, 10
.a: xor dx, dx
div cx
dec bx
add dl, '0'
mov [bx], dl
test ax, ax
jnz .a
dec bx
mov byte [bx], ' '
mov dx, bx
mov ah, 09h ; DOS.PrintString
int 21h ; -> AL='$'
add sp, 8
pop dx cx bx ax
ret
; ------------------------------
Strings dw 0
Pangram dw 0
Perfect dw 0
Codes db -1,-1,-1,-1,-1,-1,-1,-1,-1,32,32,-1,-1,32,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db 32,-1,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,44,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db -1,00,01,02,03,04,05,06,07,08,09,10,11,12,13,14
db 15,16,17,18,19,20,21,22,23,24,25,91,-1,93,-1,-1
db -1,00,01,02,03,04,05,06,07,08,09,10,11,12,13,14
db 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
db -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
TheFile db 'STR1K.JSO', 0
msgERR db 'Trouble using the file'
msgEOL db 13, 10, '$'
msgOK1 db 'Non-Pangram:$'
msgOK2 db ', Pangram:$'
msgOK3 db ', Perfect:$'
; ------------------------------
ALIGN 2
Handle rw 1
Buffer rb BUFSIZE

- 1
- 6
Definitions
Non-pangram: does not contain all 26 letters.
Pangram: contains all 26 letters at least once.
Perfect pangram: contains all 26 letters exactly once.
import string
import json
def classify_strings(filename):
with open(filename, encoding="utf-8") as f:
strings = json.load(f)
alphabet = set(string.ascii_lowercase)
counts = {
"non_pangram": 0,
"pangram": 0,
"perfect_pangram": 0
}
for s in strings:
# Normalize to lowercase and keep only alphabet letters
letters = [c for c in s.lower() if c.isalpha()]
unique_letters = set(letters)
if unique_letters == alphabet:
if len(letters) == 26: # exactly one occurrence of each
counts["perfect_pangram"] += 1
else:
counts["pangram"] += 1
else:
counts["non_pangram"] += 1
return counts
if __name__ == "__main__":
result = classify_strings("List of 1000 strings.json")
print(result)
Result
{'non_pangram': 819, 'pangram': 132, 'perfect_pangram': 49}
Explanation
819 strings are non-pangrams.
132 are pangrams (contain all 26 letters at least once).
49 are perfect pangrams (each letter exactly once).

- 63
- 1
- 5
Perfect: 49 Good: 132 Bad: 819
Code:
import json
from typing import List
with open("./strings.json") as f:
strings: List[str] = json.load(f)
perfect = 0
good = 0
bad = 0
for s in strings:
letters = [char.lower() for char in s if char.isalpha()]
if len(set(letters)) < 26:
bad += 1
elif len(letters) == 26:
perfect += 1
else:
good += 1
print(f"Perfect: {perfect}\nGood: {good}\nBad: {bad}")
import json
import string
def classify_string(s):
alphabet = set(string.ascii_lowercase)
letters = [c.lower() for c in s if c.isalpha()]
unique_letters = set(letters)
if unique_letters == alphabet:
# Count how many times each letter appears
counts = {ch: 0 for ch in alphabet}
for c in letters:
counts[c] += 1
if all(counts[ch] == 1 for ch in alphabet):
return "perfect"
return "pangram"
else:
return "non"
def classify_list(strings):
result = {"non": 0, "pangram": 0, "perfect": 0}
for s in strings:
result[classify_string(s)] += 1
return result
if __name__ == "__main__":
# Load the file with 1000 strings
with open("List of 1000 strings.json", "r", encoding="utf-8") as f:
strings = json.load(f)
counts = classify_list(strings)
print("Non-pangrams:", counts["non"])
print("Pangrams:", counts["pangram"])
print("Perfect pangrams:", counts["perfect"])
Non-pangrams: 819
Pangrams: 132
Perfect pangrams: 49
import string
def classify_strings(strings):
alphabet = set(string.ascii_lowercase)
non_pangrams = pangrams = perfect_pangrams = 0
for s in strings:
filtered = [ch.lower() for ch in s if ch.isalpha()]
letters = set(filtered)
if len(letters) < 26:
non_pangrams += 1
elif len(letters) == 26:
from collections import Counter
counts = Counter(filtered)
if all(counts[ch] == 1 for ch in alphabet):
perfect_pangrams += 1
else:
pangrams += 1
return non_pangrams, pangrams, perfect_pangrams
The count of non-pangrams, pangrams and perfect pangrams in the provided file:
- non-pangrams: 819
- pangrams: 181
- perfect pangrams: 49
My code:
def pangram_checker(strings: list[str]) -> None:
"""Determines and reports the count of non-pangrams, pangrams and perfect pangrams from a list of string.
Args:
strings (list[str]): the list of strings for pangram checking.
Returns:
None
"""
# initializing non and perfect pangram counts ('pg' -> pangram)
non_pg_count = perfect_pg_count = 0
for string in strings:
# excluding all non-alphabetic characters and making the string lowercase
lower_alphabetic_string = ''.join([ch.lower() for ch in string if ch.isalpha()])
if len(set(lower_alphabetic_string)) != 26:
# if the number of unique character is not 26, it is not a pangram
non_pg_count += 1
continue
# the control flow has come here means -> it is a pangram
if len(lower_alphabetic_string) == 26:
# the string has 26 characters and it's pangram -> it is a perfect pangram
perfect_pg_count += 1
# evaluating is done, now printing the results:
print(f"""
Pangrams count:
non-pangrams: {non_pg_count}
pangrams: {len(strings) - non_pg_count}
perfect pangrams: {perfect_pg_count}
""", sep='\n'
)
- 599
- 2
- 8
import string
import json
letters = string.ascii_lowercase
counts = [0, 0, 0, 0]
def readjson(filepath: str):
with open(filepath,"r" )as f:
data = json.load(f)
for i in range(len(data)):
store(isType(data[i].lower()))
def show():
print(f"{counts[0]} perfect pangrams")
print(f"{counts[1]} pangrams")
print(f"{counts[2]} non-pangrams")
print(f"{counts[3]} Unknows")
def store(name: str):
if name == "perfect pangrams":
counts[0] = counts[0]+1
elif name == "pangrams":
counts[1] = counts[1]+1
elif name == "non-pangrams":
counts[2] =counts[2]+1
else:
counts[3] = counts[3]+1
def isType(item:str) -> str:
result= ""
for i in range(len(letters)):
## first is it missing
if item.count(letters[i]) < 1:
return "non-pangrams"
## it has all but some have more
if item.count(letters[i])>1:
result = "pangrams"
## not non-pangrams/pangrames so it's perfect
if result == "":
return "perfect pangrams"
## edge case unlikely
else:
return result
if __name__ == "__main__":
readjson("List of 1000 strings.json")
show()
49 perfect pangrams
132 pangrams
819 non-pangrams
0 Unknows

- 45.3k
- 4
- 46
- 74
Output:
Panagram count: 132
Perfect panagram count: 49
Non-panagram count: 819
Methodology:
For each string in the passed list:
- Convert the string to lower case.
- Remove non-alpha characters using a regular expression.
- If length of the resultant string < 26, then it cannot be a pangram.
- Otherwise, add each character to a set.
- If the length of the set is not 26, then then the string cannot be a pangram.
- Otherwise the string is either a pangram or a perfect pangram depending on its length.
Code:
import re
class PangramChecker:
"""
See https://stackoverflow.com/beta/challenges/79767716/code-challenge-7-pangram-checker for
a description of what this program does.
"""
DEBUG = False # When True the pangrams are printed out
def __init__(self, strings: list[str]):
self._non_pangram_cnt = 0
self._pangram_cnt = 0
self._perfect_pangram_cnt = 0
rex = re.compile('[^a-z]')
for string in strings:
# Convert to lower case and replace non-alpha characters:
new_string = rex.sub('', string.lower())
string_lnth = len(new_string)
# Inexpensive test:
if string_lnth < 26:
self._non_pangram_cnt += 1
else:
s = set(new_string)
if len(s) != 26:
self._non_pangram_cnt += 1
elif string_lnth == 26:
self._perfect_pangram_cnt += 1
if self.DEBUG:
print('Perfect pangram:', string)
else:
self._pangram_cnt += 1
if self.DEBUG:
print('Pangram:', string)
@property
def non_pangram_cnt(self):
return self._non_pangram_cnt
@property
def pangram_cnt(self):
return self._pangram_cnt
@property
def perfect_pangram_cnt(self):
return self._perfect_pangram_cnt
if __name__ == '__main__':
import json
with open('strings.json') as f:
strings = json.load(f)
p_c = PangramChecker(strings)
print('Pangram count:', p_c.pangram_cnt)
print('Perfect pangram count:', p_c.perfect_pangram_cnt)
print('Non-pangram count:', p_c.non_pangram_cnt)
- 244.6k
- 27
- 220
- 304
Pangrams: 132 (perfect ones not included)
Perfect: 49
Non: 819
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
my $pangrams = my $perfect = my $non = 0;
my $s;
while (my $line = <>) {
next unless $line =~ /".*"/;
$line = lc($line) =~ s/[^a-z]//gr;
++$non, next if 26 > length $line; # Optimisation, 0.022s -> 0.014s.
my %char;
++$char{$_} for split //, $line;
if (26 > keys %char) {
++$non;
} elsif (grep $_ != 1, values %char) {
++$pangrams;
} else {
++$perfect;
}
}
say "Pangrams: $pangrams\nPerfect: $perfect\nNon: $non";
The optimisation line means we don't bother counting the characters if the line is shorter than 26 characters, i.e. it can't contain each letter at least once. There are still non-pangrams longer than 25 characters, though.
- 335
- 1
- 12
def classify_string(s: str) -> str:
input_filter_lower = [c.lower() for c in s if c.isalpha()]
if len(set(input_filter_lower)) != 26:
return "non-pangram"
return "perfect pangram" if len(input_filter_lower) == 26 else "pangram"
if __name__ == "__main__":
for k, v in {k: sum(classify_string(s)==k for s in open("List of 1000 strings.json").read().splitlines()[1:-1]) for k in ["non-pangram","pangram","perfect pangram"]}.items():
print(f"{k}: {v}")
non-pangram: 819
pangram: 132
perfect pangram: 49
- 795
- 6
- 21
Totals
Pangrams: 181
Of which are perfect: 49
Non-pangrams: 819
Python solution
#!/usr/bin/env python3
import json
from collections import Counter
with open('List of 1000 strings.json') as f:
ss = json.loads(f.read())
pangramsCount = 0
perfectPangramsCount = 0
totalCount = len(ss)
for s in ss:
cs = [c for c in s.lower() if ord('a') <= ord(c) <= ord('z')]
counts = Counter(cs)
if len(counts) == 26:
pangramsCount += 1
if len(counts) == counts.total() == 26:
perfectPangramsCount += 1
print(f'Pangrams: {pangramsCount}')
print(f'Of which are perfect: {perfectPangramsCount}')
print(f'Non-pangrams: {totalCount - pangramsCount}')
Learnings
After implementing this, my coffee is now no longer too hot to drink.
Expected output for the above list:
(1,1,1)
The code is as follows:
from collections import Counter
import string
def classify_strings(strings):
non_pangrams = pangrams = perfect_pangrams = 0
alphabet = set(string.ascii_lowercase)
for s in strings:
s = ''.join(ch.lower() for ch in s if ch.isalpha())
char_set = set(s)
if char_set >= alphabet:
counts = Counter(s)
if all(counts[ch] == 1 for ch in alphabet):
perfect_pangrams += 1
else:
pangrams += 1
else:
non_pangrams += 1
return non_pangrams, pangrams, perfect_pangrams
sample_strings = [
"The quick brown fox jumps over a lazy dog",
"Mr Jock, TV quiz PhD, bags few lynx",
"Hello world",
]
print(classify_strings(sample_strings))
non-pangram: 819
pangram: 132
perfect pangram: 49
def classify_string(s: str) -> str:
input_filter_lower = [c.lower() for c in s if c.isalpha()]
if len(set(input_filter_lower)) != 26:
return "non-pangram"
return "perfect pangram" if len(input_filter_lower) == 26 else "pangram"
if __name__ == "__main__":
for k, v in {k: sum(classify_string(s)==k for s in open("List of 1000 strings.json").read().splitlines()[1:-1]) for k in ["non-pangram","pangram","perfect pangram"]}.items():
print(f"{k}: {v}")
Tried my best to write my code as short as possible with keeping it still be readable.
A nice quick challenge to wake up my coding skills.
- 412
- 1
- 4
- 16
The results are in the code comments. 49, 132 and 819 respectively.
I've learned the word pangram
<?
// the $test variable contains the 1000 strings. not included as part of the answer for obvious reasons.
// $test = [...];
// initialize a var (bitmask) as the check for a pangram: 26 ones.
$complete = (1 << 26) - 1;
// initialize the counting array
$res = [];
// loop through every candidate in $test
foreach ($test as $str) {
// reset the loop-internal vars
$mask = 0;
$chars = 0;
// loop through every char of the candidate (in lowercase)
foreach (str_split(strtolower($str)) as $chr) {
// get the 0-based numeric representation of the current char
$v = ord($chr) - 97;
// skip every non-[a-z] char
if ($v > 26 || $v < 0)
continue;
// note down, that any char has come through here
$chars++;
// flip on the corresponding bit in the (loop)mask
$mask |= (1 << $v);
}
// if the loop-mask doesnt equal the check-mask, dont add anything to the counting array
if ($mask != $complete)
continue;
// push a boolean entry to the result array: true if exactly 26 chars in total have been processed a.e. a perfect pangram.
$res[] = $chars == 26;
}
// after all the input strings have been processed,
// the number of perfect pangrams is the count of the trueish values in the result array.
// in this case: ->49<-
echo "p: " . ($num_prefect = count(array_filter($res))) . "\n";
// the number of simple pangrams is the count of all values in the result array minus the perfect ones.
// in this case: ->132<-
echo "s: " . (count($res) - $num_prefect) . "\n";
// the number of non-pangrams is the number of entries in the input array minus the number of entries in the result array
// in this case: ->819<-
echo "n: " . (count($test) - count($res)) . "\n";
exit();

- 32.4k
- 6
- 42
- 68
The counts (and the output of my code):
Total Strings: 1000, Non-pangrams: 819, Pangrams: 181, Perfect Pangrams: 49
The code I wrote:
import json
def english_pangram(s: str) -> tuple[bool, bool]:
letters_only = [ch for ch in s.lower() if ch.isalpha()]
return (p := len(set(letters_only)) == 26), p and len(letters_only) == 26
def main():
with open('List of 1000 strings.json', 'r') as f:
strings = json.load(f)
pangram_count = perfect_count = 0
for s in strings:
is_pangram, is_perfect = english_pangram(s)
pangram_count += 1 if is_pangram else 0
perfect_count += 1 if is_perfect else 0
print(f'Total Strings: {len(strings)},'
f' Non-pangrams: {len(strings) - pangram_count},'
f' Pangrams: {pangram_count},'
f' Perfect Pangrams: {perfect_count}')
main()
Some thoughts:
- I considered a direct loop in Python to avoid double iteration of the characters, but making use of a comprehension and built-in functions leverages the speed you get from the C code doing the work. I also think the solution is still very readable, so overall better.
- As indicated by the name of the check function, I quickly became aware that the question is implicitly asking about English pangrams. For a language like Dutch, you'd have to deal with diacritical marks like the 'ë' in 'Israël' for example. Same for the 'ç' in 'garçon' in French. For languages like Swedish, things get worse because 'ä' is a different letter from 'a' and should be counted separately. And then there's languages where the concept of a pangram doesn't really make sense for lack of an alphabet, like Chinese.
- I thought about parallelising the work, or other optimisations, but given the size of the sample file that would greatly complicate things for very little gain. And if someone wanted this to be fast, they probably shouldn't write the code that does the work in Python to begin with. Rust would be the language of choice for me, if I wanted to go as fast as possible.
- 425
- 6
- 13
My answers:
Non-pangrams: 819
Pangrams: 132
Perfect pangrams: 49
My Java code to find these values works by reading from standard input (I copy/pasted the list of strings into System.in):
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] counts = new int[3];
// index 0,1,2 for counts of [non, reg, perfect] pangrams.
while (in.hasNextLine()) {
String s = in.nextLine();
int result = pangramChecker(s);
counts[result]++;
}
System.out.println("Non-pangrams: " + counts[0]);
System.out.println("Pangrams: " + counts[1]);
System.out.println("Perfect pangrams: " + counts[2]);
}
public static int pangramChecker(String s) {
// returns 0 if non-pangram
// returns 1 if non-perfect pangram
// return 2 if perfect pangram
s = s.toLowerCase();
int[] letterCounts = new int[26]; // a is 0, b is 1, etc
boolean nonPerf = false;
int countDistinct = 0;
for (char c : s.toCharArray()) {
if (Character.isLetter(c)) {
letterCounts[c - 'a']++;
if (letterCounts[c - 'a'] > 1)
nonPerf = true;
if (letterCounts[c - 'a'] == 1)
countDistinct++;
}
}
if (countDistinct == 26 && !nonPerf)
return 2;
else if (countDistinct == 26 && nonPerf)
return 1;
else
return 0;
}
For each string, it builds a table of 26 ints ('a' at position 0 and 'z' at position 25). It processes the string in lowercase form, char by char, ignoring every non-letter character. When a character is found, the counting table increments and the fact that it reaches 1 means a new distinct character was found. If a count ever reaches 2, it indicates that if the string is a pangram, it would not be a perfect one.
So with a single pass through each string, it maintains the number of distinct letters found and whether any repeats were found. Then if 26 distinct letters were found, the string was a pangram. And the boolean indicator nonPerf
will tell us whether any letter appeared more than once.
- 44
- 4
pacman::p_load(tidyverse, stringr, rjson, purrr, tibble)
jsonPath <- file.path("src", "List of 1000 strings.json")
jsonData <- rjson::fromJSON(paste(readLines(jsonPath), collapse = ""))
listOfStrings <- jsonData |>
str_to_lower() |>
str_split(pattern = "")
#'
#' @description Perfect pangrams contain each letter of the English alphabet exactly once. For example “Mr Jock, TV quiz PhD, bags few lynx.
IsPerfectPangram <- function(df) {
return(df |> filter(n_occurrences == 1) |> nrow() == length(letters))
}
#' @description Pangrams are phrases which contain every letter of the English alphabet at least once. For example "The quick brown fox jumps over a lazy dog.”
IsPangram <- function(df) {
return(df |> filter(n_occurrences >= 1) |> nrow() == length(letters))
}
IsNonPangram <- function(df) {
return(df |> filter(is.na(n_occurrences)) |> nrow() > 0)
}
getCategory <- function(df) {
if (df |> IsNonPangram()) {
return("non-pangram")
} else if (df |> IsPerfectPangram()) {
return("perfect pangram")
} else if (df |> IsPangram()) {
return("pangram")
}
}
CountCharacters <- function(string) {
nOccurencesByChar <- string |>
table() |>
tibble::enframe(name = "char", value = "n_occurrences") |>
filter(char %in% letters) |>
dplyr::mutate(n_occurrences = as.integer(n_occurrences))
nOccurencesByAllAlphabetChars <- data.frame(char = letters) |>
dplyr::left_join(nOccurencesByChar)
return(nOccurencesByAllAlphabetChars)
}
results <- listOfStrings |>
purrr::map_chr(
~ .x |> CountCharacters() |> getCategory() |> as.character()
)
results |> table() |> enframe(name = "category", value = "n_occurrences")
the results:
# A tibble: 3 × 2
category n_occurrences
<chr> <table[1d]>
1 non-pangram 819
2 pangram 132
3 perfect pangram 49
Non-Pangrams: 819
Pangrams: 132
Perfect Pangrams: 49
#include <bits/stdc++.h>
using namespace std;
enum Type { NON_PANGRAM, PANGRAM, PERFECT_PANGRAM };
Type classify(const string &s) {
vector<int> freq(26, 0);
for (char c : s) {
if (isalpha(c)) {
freq[tolower(c) - 'a']++;
}
}
bool allPresent = true;
bool allOnce = true;
for (int f : freq) {
if (f == 0) allPresent = false;
if (f > 1) allOnce = false;
}
if (!allPresent) return NON_PANGRAM;
if (allOnce) return PERFECT_PANGRAM;
return PANGRAM;
}
int main() {
ifstream inFile("List of 1000 strings.txt");
int nonCount=0, pangCount=0, perfectCount=0;
string line;
while (getline(inFile, line)) {
if (line.empty()) continue;
Type t = classify(line);
if(t == NON_PANGRAM) nonCount++;
else if(t == PANGRAM) pangCount++;
else perfectCount++;
}
cout << "Non-Pangrams: " << nonCount << endl;
cout << "Pangrams: " << pangCount << endl;
cout << "Perfect Pangrams: " << perfectCount << endl;
return 0;
}
- 723
- 1
- 9
- 29
- Number of non-pangrams: 819
- Number of pangrams: 181
- Number of perfect pangrams: 49
open System
open System.IO
open System.Text.Json
let filteredLines =
File.ReadAllText("List of 1000 strings.json")
|> JsonSerializer.Deserialize<string[]>
|> Array.map _.ToCharArray()
|> Array.map (Array.filter Char.IsLetter)
|> Array.map (Array.map Char.ToLower)
let isPangram chars =
let uniqueChars = chars |> Array.distinct
uniqueChars.Length = 26
let nonpangramResults =
filteredLines
|> Array.filter (isPangram >> not)
|> Array.length
Console.WriteLine($"Number of non-pangrams: {nonpangramResults}")
let pangramResults =
filteredLines
|> Array.filter isPangram
|> Array.length
Console.WriteLine($"Number of pangrams: {pangramResults}")
let isPerfectPangram chars =
chars |> isPangram && chars.Length = 26
let perfectPangramResults =
filteredLines
|> Array.filter isPerfectPangram
|> Array.length
Console.WriteLine($"Number of perfect pangrams: {perfectPangramResults}")
If you have .NET SDK installed and the text file in the same folder, run this the following way: dotnet fsi pangram-checker.fsx

- 884
- 9
- 12
Learned
This is super simple to solve with any type of scripting language, but I wanted to learn a bit mor jq syntax in depth, so
Step 1: Character counts in each string
jq 'map(split("") | group_by(.) | map({(.[0]): length}) | add)' $json_file
Step 2: Filter for letters (no whitespace, etc.)
to_entries | map(select(.key | test("[a-zA-Z]"))) | from_entries as $letter_counts
and to lower case
| to_entries | map({key: (.key | ascii_downcase), value: .value}) | group_by(.key) | map({(.[0].key): (map(.value) | add)}) | add) as $lowercase_counts
Step 3: pangram checks
($lowercase_counts | keys | length == 26) as $is_pangram
and
($is_pangram and ($lowercase_counts | to_entries | all(.value == 1))) as $is_perfect_pangram
It never ceases to amace me what you can do with simple jq transformations. :wink:
Solution
{
"perfect_pangrams": 49,
"regular_pangrams": 132,
"non_pangrams": 819,
"total": 1000
}
Full Code
#! /usr/bin/env bash
set -euo pipefail
if [ $# -ne 1 ]; then
echo "Usage: $0 <json_file>"
exit 1
fi
json_file=$1
# Derive output filename from input filename
base_name=$(basename "$json_file" .json)
output_file="${base_name}_counts.json"
# count character occurrence in each string and save to output file
jq 'map(
. as $str |
split("") |
group_by(.) |
map({(.[0]): length}) |
add as $counts |
# Extract only alphabetic characters (case-insensitive)
$counts | to_entries | map(select(.key | test("[a-zA-Z]"))) | from_entries as $letter_counts |
# Convert to lowercase for pangram checking
($letter_counts | to_entries | map({key: (.key | ascii_downcase), value: .value}) | group_by(.key) | map({(.[0].key): (map(.value) | add)}) | add) as $lowercase_counts |
# Check if all 26 letters are present (pangram)
($lowercase_counts | keys | length == 26) as $is_pangram |
# Check if all 26 letters are present exactly once (perfect pangram)
($is_pangram and ($lowercase_counts | to_entries | all(.value == 1))) as $is_perfect_pangram |
{
character_counts: $counts,
is_pangram: $is_pangram,
is_perfect_pangram: $is_perfect_pangram
}
)' "$json_file" >"$output_file"
echo "Results saved to: $output_file"
# Generate summary counts using pure jq
echo ""
echo "Summary:"
jq '
{
perfect_pangrams: [.[] | select(.is_perfect_pangram == true)] | length,
regular_pangrams: [.[] | select(.is_pangram == true and .is_perfect_pangram == false)] | length,
non_pangrams: [.[] | select(.is_pangram == false)] | length,
total: length
}
' "$output_file"
- 4.4k
- 2
- 19
- 25
I'm amazed someone else used jq for this.
There are a few useful functions you probably missed, but I imagine you learned more about how the language works without them.
- 1
- 3
non-pangrams: 819
pangrams: 132
perfect pangrams: 49
package main
import (
"bufio"
"encoding/json"
"log"
"os"
"unicode"
)
func main() {
// pangram, perfect := isPangram("BLOWZY NIGHT-FRUMPS VEX'D JACK Q")
// fmt.Printf("Pangram: %v Perfect: %v\n", pangram, perfect)
runChallenge()
}
func runChallenge() {
file, err := os.Open("challenge.json")
if err != nil {
log.Fatal(err)
}
defer file.Close()
perfectCount, pangramsCount, nonCount := 0, 0, 0
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if line == "[" || line == "]" {
continue
}
line = line[3 : len(line)-2]
pangram, perfect := isPangram(line)
if perfect {
perfectCount++
} else if pangram {
pangramsCount++
} else {
nonCount++
}
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
data := struct {
PerfectPangrams int `json:"perfectPagrams"`
Pangrams int `json:"pangrams"`
NonPangrams int `json:"nonPangrams"`
}{
PerfectPangrams: perfectCount,
Pangrams: pangramsCount,
NonPangrams: nonCount,
}
w, err := os.Create("results.json")
if err != nil {
log.Fatal(err)
}
encoder := json.NewEncoder(w)
err = encoder.Encode(data)
if err != nil {
log.Fatal(err)
}
}
func isPangram(line string) (pangram, perfect bool) {
m := makeAlphabetMap()
for _, char := range line {
lower := unicode.ToLower(char)
_, ok := m[lower]
if ok {
m[lower]++
}
}
pangram = true
perfect = true
for _, count := range m {
if count == 0 {
perfect = false
pangram = false
break
} else if count > 1 {
perfect = false
}
}
return pangram, perfect
}
func makeAlphabetMap() map[rune]int {
m := make(map[rune]int)
for _, c := range "abcdefghijklmnopqrstuvwxyz" {
m[c] = 0
}
return m
}

- 1.2k
- 8
- 17
Code
/// [dependencies]
/// serde = { version = "*", features = ["derive"] }
/// serde_json = { version = "*" }
fn main() {
// read and deserialize file
let f = std::fs::OpenOptions::new()
.read(true)
.open("./List of 1000 strings.json")
.unwrap();
let rdr = std::io::BufReader::new(f);
let strings = serde_json::from_reader::<_, Vec<String>>(rdr).unwrap();
// counters
let mut not_pangrams = 0;
let mut pangrams = 0;
let mut perfect_pangrams = 0;
for s in strings {
// strip all non alphabetic -> lowercase -> to 'a' offset
let s = s
.chars()
.filter_map(|c| {
if c.is_alphabetic() {
Some(c.to_ascii_lowercase() as u8 - 'a' as u8)
} else {
None
}
})
.collect::<Vec<_>>();
// if less than 26 cannot be pangram
if s.len() < 26 {
not_pangrams += 1;
continue;
}
// tally
let mut contains = [false; 26];
// iter through all char
for i in s.iter() {
contains[*i as usize] = true;
}
// if contain all is pangram
if contains.iter().all(|b| *b) {
// any perfect pangrams are also pangrams
pangrams += 1;
// only happens if len of stripped string is 26
if s.len() == 26 {
perfect_pangrams += 1;
}
} else {
not_pangrams += 1;
}
}
// sanity checks
assert_eq!(1000, not_pangrams + pangrams);
println!("Not Pangrams : {:>5}", not_pangrams);
println!("Pangrams : {:>5}", pangrams);
println!("Perfect Pangrams : {:>5}", perfect_pangrams);
}
Result
Not Pangrams : 819
Pangrams : 181
Perfect Pangrams : 49
- 119
- 5
Results • non-pangrams: 819 • pangrams: 181 • perfect pangrams: 49
import json
import numpy as np
with open(r"List of 1000 strings.json") as f:
data = json.load(f)
assert len(data)==1000
# list of lower case a-z in ascii representation
letters_as_nums = np.arange("a".encode("ascii")[0], "z".encode("ascii")[0]+1)
# arrays to hold results
non_pangrams=np.zeros(1000, bool)
pangrams=np.zeros(1000, bool)
perfect_pangrams=np.zeros(1000, bool)
# loop through data
for i, string in enumerate(data):
# convert string to lower case
# then convert to an array of ints in ascii representation
string_as_nums = np.array(list(string.lower().encode("ascii")))
# get array of unique characters and their counts
unique, counts = np.unique(string_as_nums, return_counts=True)
# mask of whether each character is a letter (could be punctuation)
letter_mask = np.isin(unique, letters_as_nums)
# pangram if all 26 letters
if letter_mask.sum() == 26:
# update result array
pangrams[i] = True
# perfect if there is no more than one of each letter
if counts[letter_mask].max() == 1:
# update result array
perfect_pangrams[i] = True
else: # does not have all letters -> not pangram
# update results array
non_pangrams[i] = True
assert non_pangrams.sum() + pangrams.sum() == 1000 # 1000 pangrams and non-pangrams
assert (non_pangrams + pangrams).sum() == 1000 # everything is either a pangram or not
assert pangrams[perfect_pangrams].all() # all perect pangrams are also pangrams
assert not non_pangrams[perfect_pangrams].any() # no perfect pangrams are non-pangrams
# print out results
print(
f"""
Results
\u2022 non-pangrams: {non_pangrams.sum()}
\u2022 pangrams: {pangrams.sum()}
\u2022 perfect pangrams: {perfect_pangrams.sum()}
"""
)

- 1.2k
- 10
- 22
Counts
non-pangrams: 819
pangrams: 132
perfect pangrams: 49
(edit: I didn't count the perfect pangrams in the pangrams count, bit if I should then their sum is 181)
Code
In Rust as a rustacean should do. I allowed myself to use common libs.
main.rs
use std::{fs, path::PathBuf};
use clap::Parser;
use pangram::{PangramRes, is_pangram};
#[derive(Parser, Debug)]
enum Args {
Json { file: PathBuf },
Text { sentence: String },
}
fn main() {
let args = Args::parse();
match args {
Args::Text { sentence } => match is_pangram(&sentence) {
pangram::PangramRes::NonPangram => println!("It's NOT a pangram"),
pangram::PangramRes::Pangram => println!("It's a pangram"),
pangram::PangramRes::PerfectPangram => println!("It's a PERFECT pangram"),
},
Args::Json { file } => {
let sentences: Vec<String> =
serde_json::from_str(&fs::read_to_string(file).unwrap()).unwrap();
let mut res = [0; 3];
for s in sentences {
res[is_pangram(&s) as usize] += 1;
}
println!("non-pangrams: {}", res[PangramRes::NonPangram as usize]);
println!("pangrams: {}", res[PangramRes::Pangram as usize]);
println!(
"perfect pangrams: {}",
res[PangramRes::PerfectPangram as usize]
);
}
}
}
lib.rs
#[derive(Debug, PartialEq, Eq)]
#[repr(usize)]
pub enum PangramRes {
NonPangram,
Pangram,
PerfectPangram,
}
pub fn is_pangram(s: &str) -> PangramRes {
let mut count = [0; 'z' as usize - 'a' as usize + 1];
for c in s.chars() {
let c = c.to_ascii_lowercase();
if c.is_ascii_lowercase() {
count[c as usize - 'a' as usize] += 1;
}
}
if count.contains(&0) {
PangramRes::NonPangram
} else if count.iter().any(|v| *v > 1) {
PangramRes::Pangram
} else {
PangramRes::PerfectPangram
}
}
// + test code
Cargo.toml
[package]
name = "pangram"
version = "0.1.0"
edition = "2024"
[dependencies]
clap = { version = "4.5.48", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
prompt
> cargo run json List\ of\ 1000\ strings.json
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s
Running `target/debug/pangram json 'List of 1000 strings.json'`
non-pangrams: 819
pangrams: 132
perfect pangrams: 49
Comments and other
I just found out about SO challenges a day ago, I find the concept fun. I like the idea of a pass/fail style, but this one is really easy - except if I got it wrong. I'm thinking a way to automatically check the results server-side like Codin'Game could be the way to go. Anyways, I'm gonna have fun on the other challenges I didn't start.
pangram= 181
perfect pangram= 49
not pangram= 819
first everything except english alphabet is removed.
then every characters in input string is converted into lower character and duplicates are removed.
if after filtering and removing all duplicates there are 26 characters then it must be a pangram.
but is it a perfect pangram?i.e. every character appears only once .to check that we have to see if there were 26 characters before removing duplicates.if yes then it's also perfect pangram.
note:i have considered perfect pangrams as a subset of pangrams so they are also counted in pangrams
#include <iostream>
#include <string>
#include <cctype>
#include <fstream>
#include <algorithm>
#include <unordered_set>
#include "nlohmann-json.hpp"
int pangram{0};
int perfect_pangram{0};
int not_pangram{0};
std::string filter(const std::string &s){ //removes everything except A-Z a-z
std::string result;
for (char c: s){
if(std::isalpha(static_cast<unsigned int>(c))){
result+=c;
}
}
return result;
}
void is_pangram(const std::string &s){
int original_lenth=s.length();
std::unordered_set<char> got_already;
std::string result;
for (char c :s){ //removes duplicatees
c=std::tolower(static_cast<unsigned char>(c));
if (got_already.find(c)==got_already.end()){
got_already.insert(c);
result+=c;
}
}
if (result.length()==26){ //checks if pangram
if (result.length()==original_lenth) perfect_pangram+=1;
pangram+=1;
return;
}
not_pangram+=1;
}
int main(){
std::ifstream file("List of 1000 strings.json"); //open json file
//parse json array
nlohmann::json parsed_json;
file>>parsed_json;
//iterate through the strings and pass to function
for (const auto &item:parsed_json){
std::string input= item.get<std::string>();
is_pangram(filter(input));
}
std::cout<<"pangram= "<<pangram<<std::endl;
std::cout<<"perfect pangram= "<<perfect_pangram<<std::endl;
std::cout<<"not pangram= "<<not_pangram<<std::endl;
return 0;
}
There are 49 perfect pangrams
There are 132 pangrams
There are 819 non-pangrams
Code
<?php
declare(strict_types=1);
$letters = "abcdefghijklmnopqrstuvwxyz";
$lettersParts = str_split($letters);
$strings = json_decode(file_get_contents(__DIR__ . "/list_of_1000_strings.json"), TRUE);
$lexicon = [];
$results = [
"pangrams" => [],
"perfect" => [],
"non" => [],
];
foreach($strings as $string) {
$stringParts = str_split(strtolower($string));
$isPerfect = TRUE;
$is = FALSE;
$possible = TRUE;
foreach($stringParts as $index => $character) {
if(!in_array($character, $lettersParts)) {
continue;
}
$lexicon[$string][$character] = ($lexicon[$string][$character] ?? FALSE) ? ++$lexicon[$string][$character] : 1;
if($lexicon[$string][$character] > 1) {
$isPerfect = FALSE;
}
if(count($lexicon[$string]) === 26) {
$is = TRUE;
}
if(26 - count($lexicon[$string]) > strlen($string) - $index) {
break;
}
}
if(!$is) {
$results["non"][] = $string;
continue;
}
if($isPerfect) {
$results["perfect"][] = $string;
continue;
}
$results["pangrams"][] = $string;
}
echo "There are " . count($results["perfect"]) . " perfect pangrams" . PHP_EOL;
echo "There are " . count($results["pangrams"]) . " pangrams" . PHP_EOL;
echo "There are " . count($results["non"]) . " non-pangrams" . PHP_EOL;
non-pangram = 819
pangram = 132
perfect pangram = 49
import json
import string
from enum import StrEnum, auto
from pathlib import Path
class ResultType(StrEnum):
NON_PANGRAM = auto()
PANGRAM = auto()
PERFECT_PANGRAM = auto()
def get_inputs() -> list[str]:
input_file = Path(__file__).parent.joinpath("List of 1000 strings.json")
with input_file.open() as f:
return json.load(f)
def identify_pangram(item: str) -> ResultType:
item_letters = "".join(
letter for letter in item.lower() if letter in string.ascii_letters
)
pangram = all([letter in item_letters for letter in string.ascii_lowercase])
if pangram:
if len(item_letters) == 26:
return ResultType.PERFECT_PANGRAM
return ResultType.PANGRAM
return ResultType.NON_PANGRAM
if __name__ == "__main__":
results = {result_type: [] for result_type in ResultType}
for item in get_inputs():
result_type = identify_pangram(item)
results[result_type].append(item)
for k, v in results.items():
print(f"{k}={len(v)}")
None/Pangrams/Perfects: 827/173/49
using System.Diagnostics;
using System.Text.Json;
namespace PangramAnalyzer;
internal static class PangramChecker
{
private const int AlphabetLength = 26;
private const string Path = @""; // TODO: Configure yourself
private static void Main()
{
Test();
var lines = LoadLines();
var pangrams = 0;
var perfects = 0;
foreach(var line in lines)
{
if(!IsPangram(line, out var perfect)) continue;
pangrams++;
perfects += perfect ? 1 : 0;
}
Console.WriteLine($"None/Pangrams/Perfects: {lines.Length-pangrams}/{pangrams}/{perfects}");
}
private static void Test()
{
Debug.Assert(IsPangram("Mr Jock, TV quiz PhD, bags few lynx.", out var perfect));
Debug.Assert(perfect);
Debug.Assert(IsPangram("The quick brown fox jumps over a lazy dog.", out perfect));
Debug.Assert(!perfect);
Debug.Assert(!IsPangram("This is hopefully not a pangram (^;", out perfect));
Debug.Assert(!perfect);
}
/// <summary>
/// Loads the '1000 strings' file that should be configured with <see cref="Path"/>.
/// </summary>
/// <returns>An array of lines</returns>
/// <exception cref="FileNotFoundException">If deserialization fails.</exception>
private static string[] LoadLines()
{
var text = File.ReadAllText(Path);
var lines = JsonSerializer.Deserialize<string[]>(text);
return lines ?? throw new FileNotFoundException("Pangram analysis file not found");
}
/// <summary>
/// Checks if a sentence is a (perfect) pangram.
/// </summary>
/// <param name="line">The sentence to check.</param>
/// <param name="isPerfect">Whether the pangram is perfect. False if false is returned.</param>
/// <returns>If the sentence is a pangram or not.</returns>
private static bool IsPangram(string line, out bool isPerfect)
{
// Filter for letters
var letters = line.Where(char.IsLetter).ToArray();
var isPangram = letters.ToHashSet().Count == AlphabetLength;
isPerfect = letters.Length == AlphabetLength && isPangram;
return isPangram;
}
}
you have considered A and a as different character so both of them has been counted i guess
- 61
- 6
Perfect Pangram : 49
Total Pangram : 181
Non Pangram : 819
Here is the Java code i used to solve the problem :
BufferedReader br = new BufferedReader(new FileReader("list.txt"));
// Used to keep only letter from a-z
int start = 'a';
int end = 'z';
// Read lines
List<String> lines = br.lines().toList();
// Pangrams
long pangram = lines.stream()
.map(String::toLowerCase)
.map(String::chars)
.map(is -> is.filter(code -> code >= start && code <= end)) // keep only a-z
.map(IntStream::distinct) // remove duplicate letters
.map(IntStream::count)
.filter(count -> count == 26) // keep only those with 26 letters from alphabet
.count();
// Perfect pangrams
long perfect = lines.stream()
.map(String::toLowerCase)
.map(String::chars)
.map(s -> s.filter(code -> code >= start && code <= end).toArray()) // Keep only a-z
.filter(arr -> arr.length == 26) // at this step perfect pangram should alreayd have 26 letters
.map(Arrays::stream)
.map(IntStream::distinct) // remove duplicate letter
.map(IntStream::count)
.filter(count -> count == 26) // after removing duplicate letters, should still be 26
.count();
System.out.println("Perfect Pangram : " + perfect);
System.out.println("Total Pangram : " + pangram);
System.out.println("Non Pangram : " + (lines.size() - pangram - 2));
This challenge was a nice way to practice functional style programming with Streams :)

- 187
- 3
- 15
I chose to use Python as it is the language i'm most familiar with. To check if a string is a pangram, I removed every special caracter and spaces, then removed the alphabet from it. If there is nothing leftover, the string is a pangram (P
) and to be a perfect pangram (PP
), it has to contain each letter only once so its length must be 26. If there's something leftover, then the test string did not contain all the alphabet letters, so it must not be a pangram (False
). I then apply the function to every element of the file and store the information in a dictionnary to simplify counting.
import json
with open("CodingChallenge/List of 1000 strings.json", "r") as f:
Strings = json.load(f)
def is_pangram(s):
s = ''.join(e for e in s if e.isalnum())
if not set('abcdefghijklmnopqrstuvwxyz') - set(s.lower()):
if len(s) == 26:
return 'PP'
return 'P'
else:
return False
pangrams = {'PP': 0, 'P': 0, False: 0}
for s in Strings:
type = is_pangram(s)
if type == 'PP':
pangrams['PP'] += 1
elif type == 'P':
pangrams['P'] += 1
else:
pangrams[False] += 1
print(pangrams)
Output:
{'PP': 49, 'P': 132, False: 819}
- 4.4k
- 2
- 19
- 25
This one seems pretty easy. The data is in JSON format, so jq
is the obvious tool to use.
# pangrams.jq
length as $ntotal
| map(ascii_upcase | explode
| map(select(65 <= . and . <= 90))
| sort | select((unique | length) == 26))
| [$ntotal - length, length, map(select(length == 26)) | length]
| "\(.[0]) non-pangrams and \(.[1]) pangrams, \(.[2]) of which are perfect"
$ jq -rf pangrams.jq './List of 1000 strings.json'
819 non-pangrams and 181 pangrams, 49 of which are perfect
I though this would be trickier because of jq
's limited string-processing facilities, but thanks to explode
turning strings into lists of code points, the hardest step disappeared.

- 727
- 8
- 24
output: non-pangram=819, pangram=181 perfect=49
from collections import Counter
letters = {chr(letter) for letter in range(ord('a'), ord('z')+1)}
sentences = [
"Bright vixens jump; dozy fowl quack.",
"zyra nymph, quid vex jock, fblg wt",
"Amazingly few discotheques provide jukeboxes",
...,
"Eya jchwj sqtzgx nqw",
"bqjav aovgo efit qoczrht pzqw avmskj",
"Jzaxl glnazjx iybjq ifsr fefgc ozqnxvz anlypry",
"Hnzz yvi viw kwriy lla."
]
pangram = 0
perfect = 0
def test_pangram(sentence):
includes = set(sentence) & letters
if len(includes) != 26:
return False, False
if all(symbol not in letters or value == 1 for symbol, value in Counter(sentence).items()):
return True, True
return True, False
for sentence in sentences:
is_pan, is_perfect = test_pangram(sentence.lower())
if is_pan:
pangram += 1
if is_perfect:
perfect += 1
print(f'non-pangram={len(sentences) - pangram}, {pangram=} {perfect=}')
- 318
- 1
- 13
Output:
1000
Perfect Pangrams = 49
Pangrams = 181
Non-Pangrams = 819
Code:
import json
#open file
with open('List of 1000 strings.json','r') as jsonFile:
# convert json to obj
obj = json.load(jsonFile)
# initialize counts
pngrmCnt = 0
prfctCnt = 0
nonPgCnt = 1000
strCnt = 0
# Loop through each of the strings in the obj
for strItem in obj:
# make string lowercase
lowerStr = str.lower(strItem)
# filter the string so that it includes only alphabetic characters
alphaList = list(filter(str.isalpha,lowerStr))
# assumes all strings are perfect pangrams until proven otherwise
isPerfect = True
isPangram = True
# alphabetic list must be 26 for the pangram to be perfect bc each letter exists exactly once.
if len(alphaList) != 26:
isPerfect = False
# filter out dupes from the list of alphabetic characters
noDupeList = list(set(alphaList))
# if removing all dupes reduced the list below 26, then its neither perfect, nor a pangram
if len(noDupeList) != 26:
isPerfect = False
isPangram = False
#update counts
pngrmCnt += int(isPangram)
prfctCnt += int(isPerfect)
nonPgCnt += int(isPangram) * -1
strCnt += 1
print(strCnt, end="\r")
print(f"\nPerfect Pangrams = {prfctCnt}\r\nPangrams = {pngrmCnt}\r\nNon-Pangrams = {nonPgCnt}")
- 48
- 8
Python Pangram Counter
Overview
This simple Python program can take a JSON array file of strings and count
the number of perfect pangrams, pangrams, and non-pangrams it contains. It
uses sys.argv
to take a file name and read that file.
The only argument for the command line is the name of the file.
Note: for readability, the code is found at the end of this post.
Output
Output for the provided list of 1000 strings:
49 perfect pangrams
181 total pangrams; 132 non-perfect pangrams
819 non-pangrams
Demo
Check out the demo on CodeHS! Note: for some reason, CodeHS doesn't
syntax highlight match/case
statements.
Reflection
I found it fun and relaxing to be able to set aside big projects for a bit, and to complete a fun challenge!
One thing I learned was how to use sys.argv
.
Code
This program is very simple, with only 3 files - 2 code files, plus your input file.
main.py
import json
from sys import argv
from string import ascii_lowercase
from pprint import pprint
from output_helpers import heading, print_list
def main(file_name: str):
non: list[str] = []
pangrams: list[str] = []
perfect: list[str] = []
with open(file_name) as string_file:
strings = json.load(string_file)
for string in strings:
match is_pangram(string):
case (True, True):
pangrams.append(string)
perfect.append(string)
case (True, False):
pangrams.append(string)
case _:
non.append(string)
print(heading(f"{len(perfect)} perfect pangrams:"))
# pprint(perfect)
print_list(perfect)
print()
not_perfect = tuple(filter(lambda s: s not in perfect, pangrams))
print(heading(f"{len(pangrams)} total pangrams; {len(not_perfect)}"
" non-perfect pangrams:"))
print_list(not_perfect)
print()
print(heading(f"{len(non)} non-pangrams:"))
print_list(non)
print()
print(heading("Recap:"))
print(f"{len(perfect)} perfect pangrams")
print(f"{len(pangrams)} total pangrams; {len(not_perfect)}"
" non-perfect pangrams")
print(f"{len(non)} non-pangrams")
def is_pangram(string: str) -> tuple[bool, bool]:
"""Checks whether a string is a pangram, and whether it is perfect."""
string = string.casefold()
is_pan = False
is_perfect = False
letters = []
for letter in ascii_lowercase:
letters += letter * string.count(letter)
if ''.join(letters) == ascii_lowercase:
is_pan = True
is_perfect = True
else:
letters = sorted(list(frozenset(letters)))
if ''.join(letters) == ascii_lowercase:
is_pan = True
return [is_pan, is_perfect]
main(argv[1])
output_helpers.py
from collections.abc import Collection
def heading(string: str, line_char: str="=") -> str:
"""Makes text bold, and puts a line under it."""
return f"\033[1m{string}\n{line_char * len(string)}\033[0m"
def print_list(items: Collection[str], *, bullet: str=">", tab_size:
int=4):
"""Prints a collection as a fancy (unordered) list."""
print(f" {bullet}\t\"".expandtabs(tab_size), end="")
print(f"\",\n {bullet}\t\"".expandtabs(tab_size).join(items), end="")
print("\"")

- 330
- 2
- 14
Output:
{'total_panagrams': 181, 'perf_panagrams': 49, 'not_panagrams': 819}
Code:
def find_alpha_chars(string):
all_chars = string.replace(' ', '')
return [char for char in all_chars if char.isalpha()]
def is_perf_panagram(alpha_chars):
return len(set(alpha_chars)) == len(alpha_chars)
def is_panagram(alpha_chars):
return len(set(alpha_chars)) == 26
def create_panagram_metrics(all_strings):
metrics = {
"total_panagrams": 0,
"perf_panagrams": 0,
"not_panagrams": 0
}
for string in all_strings:
lower_str = string.lower()
if len(lower_str) < 26 or len(set(lower_str)) < 26:
metrics['not_panagrams'] += 1
continue
alpha_chars = find_alpha_chars(lower_str)
if is_panagram(alpha_chars):
metrics['total_panagrams'] += 1
if is_perf_panagram(alpha_chars): metrics['perf_panagrams'] += 1
else: metrics['not_panagrams'] += 1
return metrics
def display_metrics(metrics):
print(metrics)
# where `strings` is the array of 1000 strings
display_metrics(create_panagram_metrics(strings))
Challenges
I forgot about case sensitivity lol. So some panagrams were being counted as not-panagrams. For example, abcdefghijklmnopqrstuvwxyzZ would not be considered a panagram since len(set('abcdefghijklmnopqrstuvwxyzZ')) == 26
is False
.
Solution — Code Challenge 7: Pangram Checker (C, cJSON) — Verified output and fixes
I implemented a pangram checker in C that reads list_of_1000_strings.json (array of strings), classifies each string as NON_PANGRAM, PANGRAM, or PERFECT_PANGRAM, prints overall counts, and addresses locale/character-safety issues. Running my program yields:
Non Pangram strings: 819 Pangram strings: 132 Perfect Pangram strings: 49
Problem
Given a JSON file containing 1000 strings, classify each string into:
NON_PANGRAM: does not contain every letter a–z
PANGRAM: contains every letter at least once
PERFECT_PANGRAM: contains every letter exactly once
Approach / Design
Read the JSON file (using cJSON), store strings in an array of pan_string_t.
For each string: iterate characters, normalize to lowercase, filter non-letters, map a..z to indices 0..25, increment counts.
After counting, decide category:
any letter count == 0 → NON_PANGRAM
all letters present and all counts == 1 → PERFECT_PANGRAM
all letters present but some > 1 → PANGRAM
Free all allocated resources.
Files
main.c — program entry; opens JSON, initializes structures, invokes parser, prints results, frees memory.
pangram.c — implementation: open_list, pan_str_init, load_strings_into_array, pangram_checking_parser, map_letter, print_results.
pangram.h — types and prototypes (I added Doxygen-style @brief comments).
list_of_1000_strings.json — the provided test dataset.
Makefile - Makefile to compile the executable and clean later
How to compile
Assuming cJSON is installed and available as -lcjson:
gcc -Wall -Werror main.c pangram.c -lcjson -o pangram_checker
If you use my Makefile, run:
make all
You can also run,
make clean
to clean some files the compiler created.
How to run
Put list_of_1000_strings.json in the same directory and run:
./pangram_checker
Expected console output (example from my run):
[open_list]: File was opened successfully
[pan_str_init]: Memory for the strings was allocated successfully
[pan_str_init]: Strings' properties were initialized successfully
[load_strings_into_array]: JSON strings were extracted and stored succesfully
[pangram_checking_parser]: Strings' letters where counted successfully
[pangram_checking_parser]: All strings recieved a category value successfully
====================================
Results
====================================
Non Pangram strings: 819
Pangram strings: 132
Perfect Pangram strings: 49
====================================
THE ACTUAL CODE
Makefile
################################################################
# Makefile for Code Challenge #7: Pangram checker
################################################################
CC = gcc
CFLAGS = -Wall -Werror
# Source files
SRCS = main.c pangram.c
# Object files
OBJS = $(SRCS:.c=.o)
# Output executable
TARGET = pangram_checker
# Default target
all: $(TARGET)
# Link the final program
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ -lcjson
# Compile each .c into .o
%.o: %.c pangram.h
$(CC) $(CFLAGS) -c $< -o $@
# Clean build artifacts
clean:
rm -f $(OBJS) $(TARGET)
main.c
#include <stdio.h>
#include <stdlib.h>
#include "pangram.h"
int main(void)
{
char* json_buffer = open_list();
//printf("[open_list]: [Debug]: Json buffer content %s\n", json_buffer);
pan_string_t* str_arr = pan_str_init();
load_strings_into_array(json_buffer, str_arr);
free(json_buffer);
pangram_checking_parser(str_arr);
print_results(str_arr);
for (int i = 0; i < JSON_STR_NUM; i++) free(str_arr[i].string);
free(str_arr);
return 0;
}
pangram.h
#ifndef __PANGRAM_CHECKER_H__
#define __PANGRAM_CHECKER_H__
#define JSON_STR_NUM 1000
/**
* @enum alphabet_map
* @brief Maps each lowercase English letter to an index 0–25.
*/
enum alphabet_map
{
A = 0,
B = 1,
C = 2,
D = 3,
E = 4,
F = 5,
G = 6,
H = 7,
I = 8,
J = 9,
K = 10,
L = 11,
M = 12,
N = 13,
O = 14,
P = 15,
Q = 16,
R = 17,
S = 18,
T = 19,
U = 20,
V = 21,
W = 22,
X = 23,
Y = 24,
Z = 25
};
typedef enum alphabet_map alphabet_map_t;
/**
* @enum str_category
* @brief Represents the classification of a string.
* NON_PANGRAM: does not contain all letters.
* PANGRAM: contains all letters (one or more).
* PERFECT_PANGRAM: contains each letter exactly once.
*/
enum str_category
{
NON_PANGRAM = 0,
PANGRAM = 1,
PERFECT_PANGRAM = 2
};
typedef enum str_category str_category_t;
/**
* @struct pan_string
* @brief Holds the string, its letter counts, and its pangram category.
*/
struct pan_string
{
char* string;
int alphabet_letters[26];
str_category_t category;
};
typedef struct pan_string pan_string_t;
/**
* @brief Opens the JSON file and returns its contents as a buffer.
* @return Pointer to allocated buffer containing JSON data.
*/
char* open_list();
/**
* @brief Allocates and initializes an array of pan_string_t.
* @return Pointer to allocated array of pan_string_t.
*/
pan_string_t* pan_str_init();
/**
* @brief Loads JSON strings into the given array of pan_string_t.
* @param json_buffer The raw JSON buffer containing strings.
* @param str_arr The array to populate with strings.
*/
void load_strings_into_array(char* json_buffer, pan_string_t* str_arr);
/**
* @brief Parses each string and classifies it as NON_PANGRAM, PANGRAM, or PERFECT_PANGRAM.
* @param str_arr The array of strings to analyze.
*/
void pangram_checking_parser(pan_string_t* str_arr);
/**
* @brief Maps a lowercase English character to its alphabet index.
* @param character The lowercase character to map.
* @return The corresponding alphabet_map_t index, or 0 if invalid.
*/
alphabet_map_t map_letter(char character);
/**
* @brief Prints the overall results of pangram classification.
* @param str_arr The array of classified strings.
*/
void print_results(pan_string_t* str_arr);
#endif
pangram.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <cjson/cJSON.h>
#include "pangram.h"
char* open_list()
{
FILE* fp = fopen("list_of_1000_strings.json", "r");
if (!fp)
{
printf("[open_list]: [Error]: File opening failed\n");
exit(EXIT_FAILURE);
}
printf("[open_list]: File was opened successfully\n");
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);
char* json_buffer = malloc(size + 1);
if (!json_buffer)
{
printf("[open_list]: [Error]: Malloc failed\n");
fclose(fp);
exit(EXIT_FAILURE);
}
size_t nread = fread(json_buffer, 1, size, fp);
fclose(fp);
json_buffer[nread] = '\0';
return json_buffer;
}
pan_string_t* pan_str_init()
{
int i,j;
pan_string_t* str_arr = malloc(JSON_STR_NUM * sizeof(pan_string_t));
if (!str_arr)
{
printf("[pan_str_init]: [Error]: malloc failed\n");
exit(EXIT_FAILURE);
}
printf("[pan_str_init]: Memory for the strings was allocated successfully\n");
for (i = 0; i < JSON_STR_NUM; i++)
{
str_arr[i].string = NULL;
for (j = 0; j < 26; j++) str_arr[i].alphabet_letters[j] = 0;
str_arr[i].category = NON_PANGRAM;
}
printf("[pan_str_init]: Strings' properties were initialized successfully\n");
return str_arr;
}
void load_strings_into_array(char* json_buffer, pan_string_t* str_arr)
{
cJSON *root = cJSON_Parse(json_buffer);
if (!root || !cJSON_IsArray(root))
{
printf("[load_strings_into_array]: [Error]: Invalid JSON (expected array of strings)\n");
if (root) cJSON_Delete(root);
exit(EXIT_FAILURE);
}
for (int i = 0; i < JSON_STR_NUM; i++)
{
cJSON *item = cJSON_GetArrayItem(root, i);
if (!cJSON_IsString(item) || !item->valuestring)
str_arr[i].string = strdup("");
else
str_arr[i].string = strdup(item->valuestring);
}
printf("[load_strings_into_array]: JSON strings were extracted and stored succesfully\n");
cJSON_Delete(root);
}
void pangram_checking_parser(pan_string_t* str_arr)
{
int i;
for(i = 0; i < JSON_STR_NUM; i++)
{
char* current = str_arr[i].string;
int j = 0;
for (j = 0; current[j] != '\0'; j++)
{
char lowercase_char = (unsigned char)tolower(current[j]);
if(!isalpha(lowercase_char)) continue;
str_arr[i].alphabet_letters[map_letter(lowercase_char)]++;
}
int isPangram = 0, isPerfectPangram = 0;
for(j = 0; j < 26; j++)
{
if(str_arr[i].alphabet_letters[j] == 0)
{
str_arr[i].category = NON_PANGRAM;
break;
}
else if(str_arr[i].alphabet_letters[j] > 1)
{
isPerfectPangram = 0;
isPangram++;
}
else if(str_arr[i].alphabet_letters[j] == 1)
{
isPerfectPangram++;
isPangram++;
}
}
if(isPerfectPangram == 26) str_arr[i].category = PERFECT_PANGRAM;
else if(isPangram == 26) str_arr[i].category = PANGRAM;
}
printf("[pangram_checking_parser]: Strings' letters where counted successfully\n");
printf("[pangram_checking_parser]: All strings recieved a category value successfully\n");
}
alphabet_map_t map_letter(char character)
{
switch(character)
{
case 'a':
return A;
case 'b':
return B;
case 'c':
return C;
case 'd':
return D;
case 'e':
return E;
case 'f':
return F;
case 'g':
return G;
case 'h':
return H;
case 'i':
return I;
case 'j':
return J;
case 'k':
return K;
case 'l':
return L;
case 'm':
return M;
case 'n':
return N;
case 'o':
return O;
case 'p':
return P;
case 'q':
return Q;
case 'r':
return R;
case 's':
return S;
case 't':
return T;
case 'u':
return U;
case 'v':
return V;
case 'w':
return W;
case 'x':
return X;
case 'y':
return Y;
case 'z':
return Z;
default:
printf("[map_letter]: [Error]: Make sure you use isalpha() before using me :)\n");
exit(EXIT_FAILURE);
}
}
void print_results(pan_string_t* str_arr)
{
int i = 0;
unsigned int nonPangrams = 0, pangrams = 0, perfectPangrams = 0;
for(i = 0; i< JSON_STR_NUM; i++)
{
if(str_arr[i].category == NON_PANGRAM) nonPangrams++;
else if(str_arr[i].category == PANGRAM) pangrams++;
else if(str_arr[i].category == PERFECT_PANGRAM) perfectPangrams++;
}
printf("\n====================================\n");
printf(" Results");
printf("\n====================================\n");
printf("Non Pangram strings: %d\n",nonPangrams);
printf("Pangram strings: %d\n", pangrams);
printf("Perfect Pangram strings: %d\n", perfectPangrams);
printf("====================================\n");
}
This project wil also be uploaded on my github after the official deadline comes for anyone to download:
Github profile link: link
- 39.2k
- 4
- 83
- 110
no pangram: 819
pangram: 132
perfect pangram: 49
Json.parseToJsonElement(File("""List of 1000 strings.json""").readText())
.jsonArray
.asSequence()
.map { it.jsonPrimitive.content }
.map { it.lowercase().toCharArray().filter { it in 'a'..'z' } }
.groupingBy {
if (it.distinct().size != 26) {
"no pangram"
} else if (it.size == 26) {
"perfect pangram"
} else {
"pangram"
}
}
.eachCount()
.forEach { println("${it.key}: ${it.value}") }

- 2.3k
- 3
- 23
- 34
None Pangrams 819
Pangrams 132
Perfect Pangrams 49
static void Main(string[] args) {
Console.WriteLine("Starting");
var json = File.ReadAllText("List of 1000 strings.json");
var strings = System.Text.Json.JsonSerializer.Deserialize<List<string>>(json)!.Select(i => i.ToUpper());
var countPangrams = 0;
var countNonPangrams = 0;
var countPerfectPangrams = 0;
foreach (var s in strings) {
//Remove all non alphabetic characters
var cleaned = new string(s.Where(c => char.IsLetter(c)).ToArray());
var count = cleaned.Distinct().Count();
if (count == 26 && cleaned.Length == 26) {
countPerfectPangrams++;
} else if (count == 26) {
countPangrams++;
} else {
countNonPangrams++;
}
}
Console.WriteLine("Result");
Console.WriteLine($"None Pangrams {countNonPangrams}");
Console.WriteLine($"Pangrams {countPangrams}");
Console.WriteLine($"Perfect Pangrams {countPerfectPangrams}");
Console.WriteLine("Done");
Console.Read();
}
- 2.8k
- 1
- 7
- 14
Non-pangrams: 819
Pangrams: 181
Perfect pangrams: 49
import re
import json
with open("List of 1000 strings.json", "r") as f:
strings = json.load(f)
perfect = pangram = non = 0
for text in strings:
# keep only a-z characters
clean = re.sub(r"[^a-z]", "", text.lower())
# if not 26 unique characters, must not be a pangram
if len(set(clean)) != 26:
non += 1
continue
# check if perfect
if len(clean) == 26:
perfect += 1
pangram += 1
- 98
- 9
`
pangramsCount=132, perfectPangramsCount=49, notPangramsCount=819
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
public class Main {
public record Result(Integer pangramsCount,
Integer perfectPangramsCount, Integer notPangramsCount) {}
public static void main(String[] args) {
// only added here a part of input string JSON since maximum count of words permitted is 30000 for this text box
String[] inputs = new String[]{
"Bright vixens jump; dozy fowl quack.",
"zyra nymph, quid vex jock, fblg wt",
"Amazingly few discotheques provide jukeboxes",
"GZFYRK RJMQS SYRWW NYKVE FVLPX QQDP",
"iwcles fxbgwy wltni nlkhu epqqv urnkg cpndn",
"RWITCKJ AQUBS YHIDJQ JRLOBJE CAESZQF ZOKS PBK",
};
var result = new Result(0, 0, 0);
for (String s : inputs) {
result = checkIfPangram(s, result);
}
//output: Result[pangramsCount=132, perfectPangramsCount=49, notPangramsCount=819]
System.out.println(result);
}
public static Result checkIfPangram(String inputString,
Result result) {
String sanitized = inputString.toLowerCase();
Map<Character, Integer> mappy = new HashMap<>();
for (int i = 0; i < sanitized.length(); i++) {
if (Character.isAlphabetic(sanitized.charAt(i))) {
if (mappy.containsKey(sanitized.charAt(i))) {
mappy.put(sanitized.charAt(i), mappy.get(sanitized.charAt(i)) + 1);
} else {
mappy.put(sanitized.charAt(i), 1);
}
}
}
AtomicBoolean hasOccurenceGreaterThanOnce = new AtomicBoolean(false);
mappy.forEach((character, occurence) -> {
if (occurence > 1 && !hasOccurenceGreaterThanOnce.get()) {
hasOccurenceGreaterThanOnce.set(true);
}
});
if (mappy.size() == 26) {
if (hasOccurenceGreaterThanOnce.get()) {
return new Result(result.pangramsCount + 1, result.perfectPangramsCount,
result.notPangramsCount);
} else {
return new Result(result.pangramsCount, result.perfectPangramsCount + 1,
result.notPangramsCount);
}
}
return new Result(result.pangramsCount, result.perfectPangramsCount,
result.notPangramsCount+ 1);
}
}
`
- 1.2k
- 9
- 29
Explanation:
- For cleaner code, I have used string module for lowercase letter and punctuation string. I also used built-in
str.maketrans()
andstr.translate()
method for cleaner code. Sincestr.maketrans()
require one to one character i have multiple " " * 10 so that each punctuation is mapped to " " only. - A intersting and effecient thing i found out while coding was to use
set
in order to get the pangrams list. This way i only needed to use contains_all_alpha in one list and later just reused the list_non_pangrams and list_pangrams which resulted in super fast code!
Result:
Non-Pangram count: 819
Pangram count: 181
Perfect Pangram count: 49
Code:
from string import punctuation, ascii_lowercase
orignal_pangram_check_list = [
"Bright vixens jump; dozy fowl quack.",
"zyra nymph, quid vex jock, fblg wt",
"Amazingly few discotheques provide jukeboxes",
"GZFYRK RJMQS SYRWW NYKVE FVLPX QQDP",
"iwcles fxbgwy wltni nlkhu epqqv urnkg cpndn", ...] # Trancated for submitting
# Translation Table to map punchuation to white-space
translation_table = str.maketrans(punctuation, " " * len(punctuation))
# Use translation mapping then replace(" ", "") and lower the characters.
map_line = lambda line: line.translate(translation_table).replace(" ", "").lower()
# If contains all letter then Pangrams else not pangram
def contains_all_aplha(line):
for letter in ascii_lowercase:
if letter not in line:
return False
return True
# Map can be used once only so storing as tuple for reuse
formatted_lines = tuple(map(map_line, orignal_pangram_check_list))
# Checking Logic: Any letter not present in line -> Non-Pangram,
# Pangram: all lines that are not Non-Pangrams
# Perfect Pangram: all lines in Pangrams that are having length 26 or only 26 letter
# This logic is efficent than using if (contains_all_alpha) and if (len(line) == 26 and contains_all_alpha since we dont have to re read and check each letter)
# Used sets since that allows subtraction
list_non_params = set(index for index, line in enumerate(formatted_lines) if (not contains_all_aplha(line)))
list_params = set(set(range(1000)) - list_non_params)
list_perfect_params = set(index for index in list_params if (len(formatted_lines[index]) == 26))
# Counts
print("Non-Pangram count: ", len(list_non_params))
print("Pangram count: ", len(list_params))
print("Perfect Pangram count: ", len(list_perfect_params))
# # Printing the index and line
# for index in list_non_params:
# print("Non-Pangram (index, line): ", (index, orignal_pangram_check_list[index]))
# for index in list_params:
# print("Pangram (index, line): ", (index, orignal_pangram_check_list[index]))
# for index in list_perfect_params:
# print("Perfect Pangram (index, line): ", (index, orignal_pangram_check_list[index]))

- 4.1k
- 3
- 31
- 41
function classifyStrings(strings) {
// all alphabets
const ALPHABET = 'abcdefghijklmnopqrstuvwxyz';
let nonPangramCount = 0;
let pangramCount = 0;
let perfectPangramCount = 0;
strings.forEach(str => {
const lowerStr = str.toLowerCase();
const letterCounts = {};
for (const char of lowerStr) {
if (char >= 'a' && char <= 'z') {
letterCounts[char] = (letterCounts[char] || 0) + 1;
}
}
const letterKeys = Object.keys(letterCounts);
if (letterKeys.length < 26) {
nonPangramCount++;
} else {
let isPerfect = true;
for (const letter of ALPHABET) {
if (letterCounts[letter] !== 1) {
isPerfect = false;
break;
}
}
if (isPerfect) {
perfectPangramCount++;
} else {
pangramCount++;
}
}
});
return {
nonPangrams: nonPangramCount,
pangrams: pangramCount,
perfectPangrams: perfectPangramCount
};
}
Answer:
non-Pangrams: 819,
Pangrams: 181, of which 49 are perfect Pangrams (and 132 non-perfect)
Swift Code:
import Foundation
func loadStringArray(from url: URL, decoder: JSONDecoder = JSONDecoder()) -> [String] {
do {
let data = try Data(contentsOf: url, options: [.mappedIfSafe])
return try decoder.decode([String].self, from: data)
}
catch {
print(error)
}
return []
}
if let fileName = Array(CommandLine.arguments.dropFirst()).first {
let allStrings = loadStringArray(from: URL(filePath: fileName))
let converted = allStrings.map { str in str.lowercased().filter { $0 >= "a" && $0 <= "z" } }.map {str in
var ret = Array<Int>(repeating: 0, count: 26)
str.forEach {
if let i = $0.asciiValue, i >= 97, i <= 122 { ret[Int(i-97)] += 1 }
}
return ret
}
let pangram = converted.filter { conv in conv.allSatisfy { $0 >= 1 }}
let perfectpangram = converted.filter { $0.allSatisfy { $0 == 1 }}
print("non-Pangrams: \(converted.count - pangram.count),\nPangrams: \(pangram.count), of which \(perfectpangram.count) are perfect Pangrams")
}

- 3.7k
- 2
- 22
- 27
Output
Non-pangrams: 819
Non-perfect pangrams: 132
Perfect pangrams: 49
Total pangrams (perfect and non-perfect): 181
Average time (1000 runs): 0.0041730990409851 second per run
Code
declare(strict_types=1);
function pangrams() {
// Create array of letters from A to Z with counts set to 0
$letter_counts_template = array_fill_keys(range('A', 'Z'), 0);
// A pangram will contain this many letters
$pangram_letter_count = count($letter_counts_template);
// A perfect pangram will have a count of 1 for all letters
$perfect_pangram = [
1 => $pangram_letter_count
];
// Setup counts for each type
$type_counts = [
'non-pangram' => 0,
'pangram' => 0,
'perfect-pangram' => 0
];
// Load json data file and loop through each array entry
$strings = json_decode(file_get_contents(realpath(__DIR__ . '/../data/1000-strings.json')));
foreach($strings as $string) {
// Reset letter counts by copying the template array
$letter_counts = $letter_counts_template;
// Split the string into an array of characters and
// loop through each character
foreach(str_split($string) as $char) {
// Get uppercase character for comparison
$uchar = strtoupper($char);
// If letter is not alphabetic (not A-Z), skip
if(!isset($letter_counts[$uchar])) {
continue;
}
// Otherwise, add to the count of that letter
$letter_counts[$uchar] += 1;
}
// Filter out letters with zero count
// (was not present in the sentance)
$letter_counts = array_filter($letter_counts);
/*
* If the number of letters with count greater than
* zero is equal to the pangram letter count, it is
* a pangram. Otherwise, it is not.
*/
if($pangram_letter_count == count($letter_counts)) {
/*
* If the count of unique values is the same
* as the perfect pangram's count (meaning a
* count of 1 for all letters), it is a
* perfect pangram.
* Otherwise, it is still a pangram but not
* a perfect pangram.
*/
if(array_count_values($letter_counts) == $perfect_pangram) {
$type_counts['perfect-pangram'] += 1;
} else {
$type_counts['pangram'] += 1;
}
} else {
$type_counts['non-pangram'] += 1;
}
}
return $type_counts;
};
function echo_types(array $type_counts) {
echo 'Non-pangrams: ', $type_counts['non-pangram'], PHP_EOL;
echo 'Non-perfect pangrams: ', $type_counts['pangram'], PHP_EOL;
echo 'Perfect pangrams: ', $type_counts['perfect-pangram'], PHP_EOL;
echo 'Total pangrams (perfect and non-perfect): ',
($type_counts['pangram'] + $type_counts['perfect-pangram']), PHP_EOL;
};
// How many runs should occur? Fill an array with that many zero values.
$run_until = 1;
$run_len = array_fill(0, $run_until, 0.0);
foreach($run_len as $run_key => $run) {
$time_start = microtime(true);
$type_counts = pangrams();
$time_end = microtime(true);
$run_len[$run_key] = $time_end - $time_start;
}
echo_types($type_counts);
echo PHP_EOL;
$total = array_sum($run_len);
$num_of_runs = count($run_len);
echo 'Total CPU time (', $num_of_runs, ' runs): ', $total ,' second(s) (',
($total/$num_of_runs), ' second(s) per-run average).', PHP_EOL;

- 1.2k
- 6
- 16
Pangrams: 181; perfect pangrams: 49; non-pangrams: 819
My code (in Python):
import string
def pangramchecker(phrase):
is_pangram = False
is_perfect_pangram = False
phrase = phrase.lower()
pure_letter_string = ""
alphabet = string.ascii_lowercase
for character in phrase:
if character in alphabet:
pure_letter_string += character
unique_set = set(pure_letter_string)
if len(unique_set) == 26:
is_pangram = True
if len(pure_letter_string) == 26:
is_perfect_pangram = True
return (is_pangram, is_perfect_pangram)
count_of_pangrams = 0
count_of_perfect_pangrams = 0
count_of_non_pangrams = 0
for phrase in thousandstrings:
if pangramchecker(phrase)[0]:
count_of_pangrams += 1
else:
count_of_non_pangrams += 1
if pangramchecker(phrase)[1]:
count_of_perfect_pangrams += 1
print("Pangrams: ", count_of_pangrams, ". Perfect Pangrams: ", count_of_perfect_pangrams, ". Non-pangrams:", count_of_non_pangrams)
(thousandstrings
is, of course, the list of 1,000 strings from the challenge)
The idea is to first convert the input string into all lowercase and drop non-letter characters. Then I'm converting it into a set
, which gives me all letters that appear at least once in the string. Logically, a pangram will have 26 letters (all letters of the alphabet) in the set; and a perfect pangram will be a string that's 26 letters long (every letter appearing exactly once). So I can simply use len()
on my set and string to check if it's a pangram (and, if so, even a perfect one). This result is returned as a set of two Booleans, and the main program simply keeps a running tally of these Booleans for each phrase in thousandstrings
.

- 878
- 3
- 19
This is the result I have obtained:
amount of not pangrame = 819
amount of pangrame = 132
amount of perfect pangrame = 49
And the Java code:
public class Pangrame {
int[] obtainCountOfPangramTypes() {
// I read the file as plain text.
String phrases[] = read( "src/txt.json" ).split( "\n" );
int amountOfPangrame = 0;
int amountOfNotPangrame = 0;
int amountOfPerfectPangrame = 0;
for( int i = 1; i < phrases.length - 1; i ++ ) {
switch( obtainType( phrases[ i ] ) ) {
case -1 -> amountOfNotPangrame ++;
case 0 -> amountOfPangrame ++;
case 1 -> amountOfPerfectPangrame ++;
}
}
return new int[] { amountOfNotPangrame, amountOfPangrame, amountOfPerfectPangrame };
}
int obtainType( String phrase ) {
// each position in the array corresponds to a
// letter, with position “0” being the letter “A”
int letters[] = new int[ 26 ],
found = 0;
boolean perfect = true;
for( int i = 0; i < phrase.length(); i++ ) {
// I alter the value obtained to match the position in “letters”
int value = phrase.toUpperCase().charAt( i ) - 65;
// if the condition is not met, it is not a letter
if( value < 0 || value > 25 ) {
continue;
}
// we modify the count of the letter found
letters[ value ]++;
if( letters[ value ] == 1 ) found++;
// if “perfect” is still “true” and the number of occurrences of
// the letter is greater than “1”, we assign ‘false’ to “perfect”
if( perfect && letters[ value ] > 1 ) perfect = false;
}
if( found < 26 ) return -1;
if( perfect ) return 1;
return 0;
}
public String read( String filePath ) {
String line, text = "";
File file = new File( filePath );
try( FileReader reader = new FileReader( file );
BufferedReader bufer = new BufferedReader( reader ); ) {
line = bufer.readLine();
while( line != null ) {
text = text + line + "\n";
line = bufer.readLine();
}
}
catch( IOException e ) {
System.out.println( "Wrong path" );
System.out.println("path = " + filePath );
return "";
}
return text;
}
void init() {
int result[] = obtainCountOfPangramTypes();
System.out.println( "amount of not pangrame = " + result[ 0 ] );
System.out.println( "amount of pangrame = " + result[ 1 ] );
System.out.println( "amount of perfect pangrame = " + result[ 2 ] );
}
public static void main( String[] args ) {
Pangrame aa = new Pangrame();
aa.init();
}
}
Note: I forgot to omit the first and last lines, corrected.

- 1.3k
- 1
- 10
- 21
I have written the following code in python. The file containing the strings should be placed in the same directory with the name "List of 1000 strings.json".
import re
import json
import unicodedata
def count_pangrams(sentences: list[str]) -> tuple[int, int, int]:
non_pangrams = pangrams = perfect_pangrams = 0
for sentence in sentences:
sentence = re.sub("[^a-zA-Z]", "", unicodedata.normalize("NFKD", sentence)).lower()
if len(set(sentence)) == 26:
if len(sentence) == 26:
perfect_pangrams += 1
else:
pangrams += 1
else:
non_pangrams += 1
return non_pangrams, pangrams, perfect_pangrams
if __name__ == "__main__":
with open("List of 1000 strings.json") as pangramfile:
sentences = json.load(pangramfile)
non_pangrams, pangrams, perfect_pangrams = count_pangrams(sentences)
print(f"Found {non_pangrams} non-pangram{non_pangrams != 1 and 's' or ''}, {pangrams} non-perfect pangram{pangrams != 1 and 's' or ''} and {perfect_pangrams} perfect pangram{perfect_pangrams != 1 and 's' or ''}.")
This outputs:
Found 819 non-pangrams, 132 non-perfect pangrams and 49 perfect pangrams.
The script works in a straightforward way. First, we convert the sentence to only lowercase letters. Then we count the amount of characters and unique characters in the sentence. Finally, we classify the sentence as a non-pangram, non-perfect pangram or perfect pangram accordingly.
Even though it is not explicitly mentioned in the challenge, I felt like characters with diacritic marks like accents, for example "éçƴNjĄŁⅬ", should also be taken into an account. The python unicodedata
library seems to be able to partially do this. Characters like "ƴ" (Latin Small Letter Y with Hook), and "Ł" (Latin Capital Letter L with Stroke) seem not to get parsed properly, since they are different version of a letter, not a letter combined with some diacritic mark. Since I could not find an easy way of avoiding this problem, these letters remain ignored.
I used the following testing script to identify which approach yields the best output:
test_str = "abcdéèàçùµ,€78/*@北亰ʲƛƴNjĄŁⅬ"
unicode_mode = "NFKD"
print(test_str)
print(unicodedata.normalize(unicode_mode, test_str))
print(re.sub("[^a-zA-Z]", "", unicodedata.normalize(unicode_mode, test_str)).lower())

- 119
- 3
- 13
Here is a quick answer in Python that uses sets and lists.
Thanks to a post on SO for the regex method of removing non-alphabet characters.
Usage: save the json file from the post as strings.json.
Output: 181 pangrams (of which 49 perfect), 819 non-pangrams
import re, string; pattern = re.compile(r'[\W_]+')
# convert the list of all lowercase letters to a set and list
alpha_set = set(string.ascii_lowercase)
alpha_list = list(string.ascii_lowercase)
# this functions removes non-letters and converts to lowercase
def process(string):
return pattern.sub('', string.lower())
# check if this is a pangram
def is_pangram(string):
# convert it to a set and check if it matches the letter set
# as sets don't have positional arguments or duplicate entries
# this doesn't have to be sorted or deduplicated
ls = set(string)
return ls == alpha_set
# check if this is a perfect pangram
def is_perfect(string):
# convert it to a list, sort it and compare to the letter list
ls = list(string)
ls.sort()
return ls == alpha_list
n_pangrams = 0
n_perfect = 0
n_nonpan = 0
import json
# load the file
with open("strings.json","r") as f:
pangrams = json.loads(f.read())
for pangram in pangrams:
pangram = process(pangram)
# check if this is a pangram
if is_pangram(pangram):
n_pangrams += 1
# if it is, check if it's perfect
if is_perfect(pangram):
n_perfect += 1
else:
n_nonpan += 1
print("%i pangrams (%i perfect), %i non-pangrams" % (n_pangrams, n_perfect, n_nonpan))
(base) m
- 701
- 1
- 10
- 15
Total pangrams: 132
Total perfect pangrams: 49
Total non-pangrams: 819
Learning : I learned that re.sub(r'\s+', '', s)
dosen't replaces all special characters (like !)
import os
import json
from pydoc import text
import re
def clean_str(s):
s = re.sub(r'[?|$|.|!]',r'',s)
s = re.sub(r'[^a-zA-Z0-9 ]',r'',s)
s = re.sub(r'\s+', '', s)
return s
def is_panagram(s):
alpha_set = set('abcdefghijklmnopqrstuvwxyz')
s_set = set(s.lower())
return alpha_set.issubset(s_set)
def is_perfect_panagram(s):
list_s = list(s.lower())
alpha_set = set('abcdefghijklmnopqrstuvwxyz')
if len(list_s) == len(set(list_s)) == len(alpha_set):
return True
return False
if __name__ == "__main__":
panagram = 0
perfect_panagram = 0
non_panagram = 0
with open('data.json', 'r') as f:
data = json.load(f)
for text in data:
print (f"Original text: {text}")
cleaned_text = clean_str(text)
print(f"Cleaned text: {cleaned_text}")
if is_panagram(cleaned_text):
print("The text is a pangram.")
panagram = panagram + 1
if is_perfect_panagram(cleaned_text):
print("The text is a perfect pangram.")
perfect_panagram = perfect_panagram + 1
else:
print("The text is not a pangram.")
non_panagram = non_panagram + 1
print("--------------------------------------------------")
panagram = panagram - perfect_panagram
print(f"Total pangrams: {panagram}")
print(f"Total perfect pangrams: {perfect_panagram}")
print(f"Total non-pangrams: {non_panagram}")
- 282
- 2
- 11
Vyxal 3, 18 bytes
#?ƛʀ⦷ka∦⊍Þ⊍ɦ¬&¨¬}∑
#?ƛʀ⦷ka∦⊍Þ⊍ɦ¬&¨¬}∑
#? # wrap all lines of input in a list
ƛ } # map over that list:
ʀ⦷ # toLowerCase, keep only letters
∦ # parallel apply wrap: apply the next 2 operations
# on the same inputs at the same time, and wrap the result in a list
⊍ # set difference
Þ⊍ # and multiset difference
ka # with builtin constant Lowercase Alphabet
# we get a list of 2 lists.
# the first list is the missing letters to form a pangram
# the second list is the same, but it also contains letters that are present twice
ɦ¬& # append the reverse of thee first list (ie whether is is NOT a pangram) to that list
¨ # to each list
¬ # cast them to a boolean (true if non-empty), then negate the result.
# at the end of the lambda, the input is transformed into a list of lists,
# where the first element of each list is whether it's a pangram
# the second element is whether it is also a perfect pangram,
# and the last element whether is is neither.
∑ # sum the columns of the list (casting true to 1 and false to 0)
💎
Created with the help of Luminespire.
the result is 181 pangrams and 49 perfect ones, leaving 819 regular sentences:
❯ cat List\ of\ 1000\ strings.txt | java -jar vyxal-3.10.0.jar --code '#?ƛʀ⦷ka∦⊍Þ⊍ɦ¬&¨¬}∑' --stdin
[181, 49, 819]

- 1.1k
- 2
- 18
- 29
Doesn't output the number of non-pangrams (not so mogged now :p)
- 282
- 2
- 11
fixed for 3 bytes. the mogging will continue until score improves.
- 106
- 7
My Code
# The solution is written in python
from typing import Tuple
import json
def is_pangram(string)->bool:
a_z = "abcdefghijklmnopqrstuvwxyz"
for letter in a_z :
if letter.lower() not in string:
return False
return True
def count_pangrams(lst)->Tuple[int, int, int]:
num_pangrams = 0
num_perfect_pangrams = 0
num_non_pangrams = 0
for string in lst:
if not is_pangram(string):
num_non_pangrams += 1
elif len(set(string.replace(" ",""))) == len(string.replace(" ","")):
num_perfect_pangrams += 1
else:
num_pangrams += 1
return ( num_non_pangrams, num_pangrams, num_perfect_pangrams)
list_of_strings = []
try:
with open('List of 1000 strings.json','r') as file:
list_of_strings = json.load(file)
except FileExistsError:
sys.exit('File not found!')
# print(list_of_strings)
non_pangrams,pangrams, perfect_pangrams = count_pangrams(list_of_strings)
print(f'Non pangrams: {non_pangrams}', f'Pangrams: {pangrams}', f'Perfect pangrams: {perfect_pangrams}', sep='\n')
# Output:
# Non pangrams: 937
# Pangrams: 52
# Perfect pangrams: 11
- 414
- 2
- 5
819 132 49 (non-pangrams, pangrams, perfect pangrams)
# Load the file
import json
# I renamed the file. Why would you name it something with spaces in it!!
test_strings = json.load(open('strings.json','r'))
alphabet = 'abcdefghijklmnopqrstuvwxyz'
def test_pangram(poss_pang):
# Let's do this with 1 pass through the string for speed
dct = {key:0 for key in alphabet}
for entry in poss_pang:
entry = entry.lower()
for char in entry:
if char in dct:
dct[char] += 1
perfect = True
for key in dct:
if dct[key] == 0:
return 0
if dct[key] > 1:
perfect = False
if perfect:
return 2
return 1
perfects, pans, nots = 0,0,0
for test in test_strings:
out = test_pangram(test)
if out == 0:
nots += 1
elif out == 1:
pans += 1
elif out == 2:
perfects += 1
else:
raise("Broken!")
print(nots, pans, perfects)
number of pengrams 132 number of perfect pengrams 49 number of non pengrams 819
const stringsToTest = require('./stringsToTest.json');
const main = function(strings) {
const result = {
numNonPengrams: 0,
numPengrams: 0,
numPerfectPengrams: 0
};
for(let i = 0; i < strings.length; i++) {
const checkResult = pengramChecker(strings[i]);
result[checkResult] += 1;
}
return result;
}
const pengramChecker = function(strToTest, flag) {
const regex = /[a-z]/g;
const matches = strToTest.toLowerCase().match(regex);
const uniqueMatches = new Set(matches || []);
if(uniqueMatches.size < 26) {
return "numNonPengrams";
}
if(uniqueMatches.size === matches.length && matches.length === 26) {
return "numPerfectPengrams"
}
return "numPengrams"
}
const { numPengrams, numPerfectPengrams, numNonPengrams} = main(stringsToTest)
console.log(" number of pengrams", numPengrams);
console.log("\n number of perfect pengrams", numPerfectPengrams);
console.log("\n number of non pengrams", numNonPengrams)
module.exports = { main };

- 6.7k
- 3
- 19
- 35
I did it in pyspark.
there are 819 non-pangrams and 49 perfect pangrams. there are 132 pangrams excluding the perfect pangrams. the number of pangrams are 181 if you include perfect pangrams as well considering they're "pangrams".
import pandas as pd
import pyspark.sql.functions as func
file_path = './drive/MyDrive/Copy of List of 1000 strings.json'
data_sdf = spark.createDataFrame(pd.read_json(file_path), ['strings'])
pre_process_sdf = data_sdf. \
withColumn('strings_lower', func.lower('strings')). \
withColumn('string_letter_split',
func.filter(func.split(func.regexp_replace('strings_lower', '[^a-z]', ''), ''), lambda x: x.isin('', ' ') == False)
). \
withColumn('distinct_letters', func.array_distinct('string_letter_split')). \
withColumn('actual_size', func.size('string_letter_split')). \
withColumn('distinct_size', func.size('distinct_letters'))
pre_process_sdf. \
withColumn('non_pangram', (func.col('distinct_size') < 26).cast('int')). \
withColumn('pangram', (func.col('distinct_size') == 26).cast('int')). \
withColumn('perfect_pangram', ((func.col('pangram') == 1) & (func.col('actual_size') == 26)).cast('int')). \
select(func.sum('non_pangram').alias('non_pangrams'),
func.sum('pangram').alias('pangrams'),
func.sum('perfect_pangram').alias('perfect_pangrams'),
func.sum(func.when(func.col('perfect_pangram') == 0, func.col('pangram'))).alias('pangrams_excl_perfects')
). \
show()
# +------------+--------+----------------+----------------------+
# |non_pangrams|pangrams|perfect_pangrams|pangrams_excl_perfects|
# +------------+--------+----------------+----------------------+
# | 819| 181| 49| 132|
# +------------+--------+----------------+----------------------+
- 612
- 1
- 6
- 19
I took this challenge as an opportunity to improve my C++ skills. Here's what I came up with:
Code:
/* pangram_checker.cpp */
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
int nonpangram_count = 0;
int pangram_count = 0;
int perfect_pangram_count = 0;
ifstream input_file("List of 1000 strings.json");
for (string line; getline(input_file, line);) {
if (line.length() <= 1) {
// Not a sentence (includes '[' and ']' lines in the json)
continue;
}
int letters_count[26] = { }; // Array of counters for each letter
int count_unique = 0; // How many unique letters counted
bool is_pangram;
bool is_perfect = true;
for (char letter : line) {
int letter_index;
if ('A' <= letter && letter <= 'Z') {
letter_index = letter - 'A';
} else if ('a' <= letter && letter <= 'z') {
letter_index = letter - 'a';
} else {
// Not a letter (includes '"' ',' and whitespace in the json)
continue;
}
if (letters_count[letter_index]++) {
// This letter has already been counted, not perfect
is_perfect = false;
} else {
// First time counted, is a new letter
count_unique++;
}
}
if (count_unique < 26) {
// Failed to count all 26 letters
nonpangram_count++;
} else {
pangram_count++;
if (is_perfect) {
perfect_pangram_count++;
}
}
}
cout << "Non-pangrams: " << nonpangram_count << endl;
cout << "Pangrams: " << pangram_count << endl;
cout << "Perfect pangrams: " << perfect_pangram_count << endl;
}
Compile:
$ g++ -o pangram_checker pangram_checker.cpp
$ ./pangram_checker
Output:
Non-pangrams: 819
Pangrams: 181
Perfect pangrams: 49
Normal Sentences | Pangrams | Perfects |
---|---|---|
819 | 132 | 49 |
I was bored, and I thought it would be fun to partake in one of these. I know, my coding sucks and is overcomplicated (useless alphabet array!), but hey, I qualified, right‽
var sentences = [ ... ]
var alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", /*and*/ "z"] //Now I know my ABCs! next time won't you sing with me?
for (i=0; i < 1000; i++) {
s = sentences[i];
s1 = s.toLowerCase().replace(/[\s\p{P}_]/gu, '')
s2 = s1.split('').sort().join('');
if (s2.split("").join("") === alphabet.join("")) {
s3 = "a perfect panagram!";
}
else if ([...new Set(s2.split(""))].join("") === alphabet.join("")) {
s3 = "an imperfect panagram!";
}
else {
s3 = "a normal sentence.";
}
console.log(
"#" + i + ". '" + s + "' lowercased and un-punctuated is '" + s1 + "', and it alphabetized is '" + s2 + "', so, it is " + s3
);
}
Run it here: https://www.programiz.com/online-compiler/4TvCHdnizWti8
Below is a Python program that determines the count of non-pangrams, pangrams, and perfect pangrams from a list of strings. A pangram contains every letter of the English alphabet at least once, while a perfect pangram contains each letter exactly once (ignoring case and non-letter characters).
def is_pangram(text):
# Convert to lowercase and filter only alphabetic characters
alphabet = set(char.lower() for char in text if char.isalpha())
# Check if all 26 letters are present
return len(alphabet) == 26
def is_perfect_pangram(text):
# Convert to lowercase and filter only alphabetic characters
alphabet = set(char.lower() for char in text if char.isalpha())
# Check if exactly 26 unique letters are present
return len(alphabet) == 26 and len(set(text.lower())) == 26
def count_pangram_types(string_list):
non_pangrams = 0
pangrams = 0
perfect_pangrams = 0
for string in string_list:
if not is_pangram(string):
non_pangrams += 1
elif is_perfect_pangram(string):
perfect_pangrams += 1
else:
pangrams += 1
return non_pangrams, pangrams, perfect_pangrams
# Example usage with a small list (replace with your 1,000 strings)
test_strings = [
"The quick brown fox jumps over a lazy dog",
"Mr Jock, TV quiz PhD, bags few lynx",
"Hello world"
]
non_p, pang, perf_pang = count_pangram_types(test_strings)
print(f"Non-pangrams: {non_p}")
print(f"Pangrams: {pang}")
print(f"Perfect pangrams: {perf_pang}")

- 469
- 6
- 15
Results
$ for i in {1..5}; do time go run pangram_checker List_of_1000_strings.json;done
non_pangrams: 819, pangrams: 132, perfect_pangrams: 49
real 0m0.540s
user 0m0.182s
sys 0m0.310s
non_pangrams: 819, pangrams: 132, perfect_pangrams: 49
real 0m0.187s
user 0m0.162s
sys 0m0.117s
non_pangrams: 819, pangrams: 132, perfect_pangrams: 49
real 0m0.177s
user 0m0.162s
sys 0m0.127s
non_pangrams: 819, pangrams: 132, perfect_pangrams: 49
real 0m0.178s
user 0m0.123s
sys 0m0.169s
non_pangrams: 819, pangrams: 132, perfect_pangrams: 49
real 0m0.181s
user 0m0.156s
sys 0m0.126s
Source code
file: pangram_checker.go
package main
import (
"fmt"
"encoding/json"
"os"
"strings"
)
func countPangrams(lines []string) (uint16, uint16, uint16) {
var nonPangrams, pangrams, perfectPangrams uint16
for _, line := range lines {
var letterMask uint32 = 0
var letterCount uint16 = 0
for i := 0; i < len(line); i++ {
char := line[i]
if char >= 'A' && char <= 'Z' {
char += 32
}
if char >= 'a' && char <= 'z' {
letterCount++
bit := uint32(1) << (char - 'a')
letterMask |= bit
}
}
uniqueCount := uint16(popcount(letterMask))
if uniqueCount == 26 {
if letterCount == 26 {
perfectPangrams++
} else {
pangrams++
}
} else {
nonPangrams++
}
}
return nonPangrams, pangrams, perfectPangrams
}
func popcount(x uint32) uint16 {
var count uint16 = 0
for x != 0 {
x &= x - 1
count++
}
return count
}
func readFile(filename string) []string{
file, err := os.Open(filename)
if err != nil {
fmt.Printf("Error opening file: %v\n", err)
os.Exit(1)
}
defer file.Close()
var rawLines []string
decoder := json.NewDecoder(file)
err = decoder.Decode(&rawLines)
if err != nil {
fmt.Printf("Error parsing JSON: %v\n", err)
os.Exit(1)
}
// Strict filtering
lines := make([]string, 0, len(rawLines))
for _, line := range rawLines {
trimmed := strings.TrimSpace(line)
if trimmed != "" && trimmed != "null" {
lines = append(lines, line)
}
}
return lines
}
func main() {
if len(os.Args) < 2 {
panic("invalid usage")
}
lines := readFile(os.Args[1])
non, reg, perfect := countPangrams(lines)
fmt.Printf("\nnon_pangrams: %d, pangrams: %d, perfect_pangrams: %d", non, reg, perfect)
}
What i LearneD?
Using a 32-bit integer with bitwise operations (
letterMask |= bit
) to track letters was significantly faster than usingmap[rune]bool
. Each letter maps to a bit position, and checking for all 26 letters becomes a simple comparison with0x3FFFFFF
.Early exit optimization: Once all 26 bits are set in the letter mask, we can immediately break out of the character loop. This saves processing time on longer pangram strings.
Data type sizing matters: Using
uint16
instead ofint
for counters reduced memory usage since we only need to count up to 1000. Pre-allocating the slice with exact capacity eliminated reallocation overhead.The final implementation processes 1000 strings in approximately 3 milliseconds, achieving roughly 333,000 strings per second on an i7-9750H CPU.

- 4.8k
- 2
- 18
- 43
Summary
Simple approach where a dictionary kept the counts of the characters in the words. The counts are incremented as letters appear in each word. The letter counts are checked and used to determine if a word is a pangram, perfect pangram or non pangram once the characters in a word have been checked.
Looking forward to see if anyone else has done something a bit more interesting / clever.
*
Note: I have listed pangrams and perfect pangrams exclusively i.e. perfect pangrams were not also listed as pangrams.*
Results
Non-pangram count: 819
Pangram count: 132
Perfect pangram count: 49
Code
public class Program
{
private const int CapitalAAsciiValue = 65;
private const int CapitalZAsciiValue = 90;
private static Dictionary<char, int> _letterCounts = new Dictionary<char, int>();
static void Main(string[] args)
{
var pangramCount = 0;
var nonPangramCount = 0;
var perfectPangramCount = 0;
InitialiseLetterCounts();
var words = ParseInputFile(args[0]);
foreach (var word in words)
{
UpdateLetterCountsForWord(word);
if (IsLastWordAPerfectPangram())
{
++perfectPangramCount;
}
else if (IsLastWordAPangram())
{
++pangramCount;
}
else
{
++nonPangramCount;
}
ResetCounts();
}
Console.WriteLine($"Non-pangram count: {nonPangramCount}");
Console.WriteLine($"Pangram count: {pangramCount}");
Console.WriteLine($"Perfect pangram count: {perfectPangramCount}");
}
private static string[] ParseInputFile(string filePath)
{
var file = File.ReadAllText(filePath);
return JsonSerializer.Deserialize<string[]>(file);
}
private static void InitialiseLetterCounts()
{
for (int i = CapitalAAsciiValue; i <= CapitalZAsciiValue; ++i)
{
_letterCounts[Convert.ToChar(i)] = 0;
}
}
private static void ResetCounts()
{
foreach (var key in _letterCounts.Keys)
{
_letterCounts[key] = 0;
}
}
private static void UpdateLetterCountsForWord(string word)
{
foreach (var character in word)
{
var key = char.ToUpper(character);
if (_letterCounts.ContainsKey(key))
{
_letterCounts[key] += 1;
}
}
}
private static bool IsLastWordAPangram()
{
return _letterCounts.All(x => x.Value >= 1);
}
private static bool IsLastWordAPerfectPangram()
{
return _letterCounts.All(x => x.Value == 1);
}
}
- 19
- 3
code:
import string
import json
from collections import Counter
def is_pangram(text: str) -> int:
alphabet = set(string.ascii_lowercase)
filtered = [c for c in text.lower() if c in alphabet]
counts = Counter(filtered)
if not alphabet <= set(filtered):
return 0 # not a pangram
elif all(count == 1 for count in counts.values()) and len(filtered) == 26:
return 1 # perfect pangram
else:
return 2 # pangram
def main():
file_path = '/content/drive/MyDrive/List of 1000 strings.json'
with open(file_path, 'r') as f:
data = json.load(f)
arr = [0, 0, 0]
for text in data:
arr[is_pangram(text)] += 1
print(f"non-pangrams: {arr[0]}\npangrams: {arr[2]}\nperfect pangrams: {arr[1]}")
if __name__ == "__main__":
main()
output:
non-pangrams: 819
pangrams: 132
perfect pangrams: 49
- 10.8k
- 4
- 46
- 68
Count:
non-pangrams: 819
pangrams: 181
perfect: 49
Code (js):
let count = {
non: 0,
pan: 0,
perfect: 0
}
words.forEach(word => {
const w = word.replaceAll(/[\W]/g,'').toLowerCase()
if (new Set(w.split('')).size === 26) {
count.pan += 1
if (w.length === 26) {
count.perfect += 1
}
} else {
count.non += 1
}
})
- 399.7k
- 49
- 474
- 671
pangrams: 181, perfect pangrams: 49, others: 819
#include <algorithm>
#include <print>
#include <ranges>
#include <string_view>
using std::ranges::all_of;
static inline constexpr auto count(std::string_view s) {
std::array<unsigned, 26> histo{};
for (char c : s) if (std::isalpha(c)) ++histo[std::tolower(c) - 'a'];
return histo;
}
int main() {
size_t pangram = 0, perfect_pangram = 0, other = 0;
for (std::string_view sv : {
"Bright vixens jump; dozy fowl quack.",
...
}) {
auto h = count(sv);
if (all_of(h, std::identity{})) {
pangram += 1;
perfect_pangram += all_of(h, [](auto n) { return n == 1; });
} else
other += 1;
}
std::println("pangrams: {}, perfect pangrams: {}, others: {}", pangram, perfect_pangram, other);
}
The challenge failed to specify how input was to be consumed, how to deal with case conversion/collations (Unicode?) and how to deal with non-alpha characters. So I made the simplest choices that seemed right.

- 15.2k
- 11
- 26
- 42
819 non-pangrams, so 181 pangrams among which 49 perfect (and 142 non-perfect).
from math import prod
from collections import Counter
from json import load
# Read a list of 1000 histograms
with open('List of 1000 strings.json') as f: L=(Counter(x.lower()) for x in load(f))
# Turn it in a list of product of number of occurrences
p=[prod(c[chr(a)] for a in range(ord('a'),ord('z')+1)) for c in L]
# if a product is 0, one letter has 0 occurrence=>not pangram. If 1⇒all 1⇒perfect. Otherwise, non-perfect pangram
sum(x==0 for x in p), sum(x>0 for x in p), sum(x==1 for x in p)
# (819, 181, 49)
Of course, the heavy lifting here is done by Counter
. But the whole point of coding in python is to rely on the rich existing API (otherwise, if we were to code in pure python, it is just a very slow and CO₂ emitting language).
Since there are only 1000 items in the list I read the whole list, and then transform it in other whole lists. That is negligible before the minimal memory usage of even an empty python program. But if the list were to be bigger, it would be necessary to process "on the fly"
- 11
- 2
Written in Groovy
package ls91.stackoverflow.challenges.c7
import groovy.json.JsonSlurper
// https://stackoverflow.com/beta/challenges/79767716/code-challenge-7-pangram-checker
enum PangramResult {
NON_PANGRAM, PANGRAM, PERFECT_PANGRAM
}
static PangramResult isPangram(String string) {
def characters = string.toUpperCase().toList()
characters.removeIf {
!it.matches('[A-Z]')
}
def characterCounts = characters.countBy()
if (characterCounts.size() != 26) {
return PangramResult.NON_PANGRAM
}
def uniqueCounts = characterCounts.collect {it.value}.unique()
return (uniqueCounts.size() == 1 && uniqueCounts[0] == 1) ? PangramResult.PERFECT_PANGRAM : PangramResult.PANGRAM
}
static void main(String[] args) {
JsonSlurper jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parse(new File(args[0]))
println object.collect {
isPangram(it as String)
}.countBy()
}
Result:
[PANGRAM:132, NON_PANGRAM:819, PERFECT_PANGRAM:49]

- 26.7k
- 5
- 27
- 56
With awk:
awk '$1 !~ /[][]/ {
split($0, a, "")
max = 0
for (i in a) {
if (a[i] ~ /^[[:alpha:]]$/) {
b[a[i]]++
if (b[a[i]] > max) {
max = b[a[i]]
}
}
}
if (length(b) == 26 && max == 1) {
perfect_pangrams++
} else if (length(b) >= 26 && max >= 1) {
pangram++
} else {
not_a_pangram++
}
delete a
delete b
}
END {
print "perfect pangrams =", perfect_pangrams ",",
"non-perfect pangrams =", pangram ",",
"not pangrams =", not_a_pangram ",",
"total pangrams = " perfect_pangrams + pangram
}' List\ of\ 1000\ strings.json
perfect pangrams = 49, non-perfect pangrams = 132, not pangrams = 819, total pangrams = 181
What did I learn: I had to ignore lines with only "[" and "]" and it quickly got too complicated for a one-liner.

- 1
- 5
- 28
Language: PHP
First Bitmask: A bitmask with 26 bits is used to efficiently track letter presence, where each bit represents a letter from 'a' to 'z'.
Each string is converted to lowercase and stripped of non-alphabetic characters to focus solely on letter analysis.
Pangram Check: if its bitmask matches the target mask (all 26 bits set), indicating all letters are present at least once.
Perfect Pangram Check: if the bitmask matches the target mask and the cleaned string length is exactly 26, ensuring no duplicate letters.
$listOfStrings = [
// Just copy paste whole string from list of 1000 strings file
];
$result = categorizeStringsForPangramCheck($listOfStrings);
function categorizeStringsForPangramCheck(array $string_list): array
{
$pangramCount = 0;
$nonPangramCount = 0;
$perfectPangramCount = 0;
$targetMask = (1 << 26) - 1; // This is a binary number where all 26 bits are set to 1. // 26 ones 111.....
foreach ($string_list as $string) { // Now taking each string from the list
// Clean the string: convert to lowercase and remove non-alphabetic characters
$cleanedString = preg_replace('/[^a-z]/', '', strtolower($string));
$letterMask = 0; // This will hold the bitmask count
$letterCount = strlen($cleanedString); // cleaning string count
for ($i = 0; $i < $letterCount; $i++) {
$char = $cleanedString[$i];
$bitPosition = ord($char) - ord('a');
$letterMask |= (1 << $bitPosition);
}
$isPangram = ($letterMask == $targetMask);
$isPerfect = $isPangram && ($letterCount == 26);
if ($isPerfect) {
$perfectPangramCount++;
} elseif ($isPangram) {
$pangramCount++;
} else {
$nonPangramCount++;
}
}
return [
'pangrams' => $pangramCount,
'non_pangrams' => $nonPangramCount,
'perfect_pangrams' => $perfectPangramCount,
];
}
output:
array:3 [
"pangrams" => 132
"non_pangrams" => 819
"perfect_pangrams" => 49
]
- 199.4k
- 23
- 252
- 321
In Ruby:
require 'json'
def count_pangrams(strs)
pangrams = perfect_pangrams = 0
strs.each do |str|
# get rid of all but English letters - using regex is easiest
letters = str.downcase.gsub(/[^a-z]/, '').chars
num_uniq_letters = letters.uniq.length
# in an English pangram the count of unique letters has to be 26
if num_uniq_letters == 26
pangrams += 1
# for a perfect pangram, it is also the count of non-unique letters
perfect_pangrams += 1 if letters.length == num_uniq_letters
end
end
[strs.length - pangrams, pangrams, perfect_pangrams]
end
strs = JSON.parse(File.read('List of 1000 strings.json'))
nonpangrams, pangrams, perfect_pangrams = count_pangrams(strs)
puts "Non-pangrams: #{nonpangrams}"
puts "Pangrams: #{pangrams}"
puts "Perfect pangrams: #{perfect_pangrams}"
# Non-pangrams: 819
# Pangrams: 181
# Perfect pangrams: 49

- 1.1k
- 2
- 18
- 29
Vyxal 3, 46 bytes
eƛ~ɾ“ʀS:u;ka=1&1FwṪ}∑"ƛƛiṬ▲2⎇¨\ø¹∧F_:w«⎂?[⑴”$%
The counts are:
Perfect: 49
Pangram: 132
Neither: 819
Expects the input to be a single string with each list item on its own line (I tried list input, but there was something weird happening with the input parser with that many items).
Yes, that really is 46 bytes. Vyxal 3 uses a custom Single Byte Character Set (SBCS) to encode programs in a visually appealing way. The raw bytes are:
65 01 7E E2 FE E0 53 3A 75 3B 6B 61 3D 31 26 31 46 77 E5 7D 82 22 01 01 69 E4 E3 32 0E 1C 5C FC A7 EA 46 5F 3A 77 8A 18 3F 5B 14 FF 24 25
Algorithm Explained
The core idea here is to iterate over each string in the input, determine whether it's perfect, a normal pangram, or neither, and collect the results into a single list.
For each string in the input, it needs to be stripped of any non-letter characters and converted to lowercase. This makes the string easier to manipulate. These will be referred to as "modified strings"
Checking for a perfect pangram is easy - a modified string is a perfect pangram if, when sorted, it equals the string "abcdefghijklmnopqrstuvwxyz"
(represented as ka
in the code - there's shortcut for it).
Checking for a normal pangram requires an extra step of removing duplicate letters after sorting.
Within the program, the results of checking each category of pangramness is stored in a list like [isPerfect, isPangram]
. This will be one of [1, 1]
, [0, 1]
, [0, 0]
.
While helpful, this does not lend itself well to separating perfect and normal pangram counts - if you try to aggregate a list of these lists via summing, perfect pangrams will be double counted. And it also does not account for the count of non-pangrams.
Therefore, I do a little code golf magic (TM) to turn this list into something that distinctly identifies whether a string is perfect, pangram, or neither. My thinking here was that the main differing feature is the index of the first 1
in the list. This would map perfect pangrams to 0
and normal pangrams to 1
. However, this still doesn't account for non-pangrams.
To remedy this, I append a 1
to the [isPerfect, isPangram]
list to ensure there is always a 1
, consequently mapping non-pangrams to 2
.
0
, 1
, and 2
are then mapped to [1,0,0]
, [0,1,0]
and [0,0,1]
respectively (i.e. a 1
is placed at the corresponding index). This neatly represents [isPerfect, isPangramButNotPerfect, isNeither]
.
Such a list of lists can then be summed column-wise to get the final result.
Notably, there's some additional nuance to how this is all done during program execution. But this high level explanation is enough to explain pretty much what's going on here.
Program Explained
eƛ~ɾ“ʀS:u;ka=1&1FwṪ}∑"ƛƛiṬ▲2⎇¨\ø¹∧F_:w«⎂?[⑴”$%
e # Split the input on newlines
ƛ } # To each candidate string:
~ɾ # Remove all non-letter characters (i.e. filter by isLetter)
“ # Convert to a single string because the filter leaves the string as a list of characters
ʀ # Convert that to lowercase. We'll call this string x
S:u; # Create a list of [sorted(x), uniqueLettersOnly(sorted(x))]
ka= # And compare each item in that list to the string "abcdefghijklmnopqrstuvwxyz". This automatically performs the equality check for each item in the list through automatic vectorisation (think APL type array programming)
1& # Append a 1 to that list
1Fw # And find the first 1 in that list. You'll need to read the algorithm overview to understand why I'm doing this.
Ṫ # Create a list of at most 3 items where the item at index (first 1) is 1, and where every other item is 0
∑ # Sum the entire list to be left with the list [perfect, pangram, neither]
"ƛƛiṬ▲2⎇¨\ø¹∧F_:w«⎂?[⑴” # This is just a compressed representation of the string "Perfect: %\nPangram: %\nNeither: %". The `%`s will be used for string formatting.
$% # Format that string with the items of the list we summed. The items in the list will be corresponded to the format string, so the first `%` will be replaced with `perfect`, the second `%` will be replaced with `pangram` and the third `%` will be replaced with `neither`.
💎
Explaination created with the help of Luminespire. It's a code explaination formatting tool I made for the fine folk of the Code Golf StackExchange. Notably, there's 0 AI involved with the tool.

- 1.1k
- 2
- 18
- 29
"Why not use a for loop or variables or if statements?" because array programming, functional programming, and tacit programming go brrr.

- 1.1k
- 2
- 18
- 29
In case anyone is going to comment about it not being 46 bytes, I refer you to https://en.wikipedia.org/wiki/SBCS for reading about Single Byte Character Sets.
And yes, you can run the interpreter with both Utf8 and vyxal bytes.

- 4.8k
- 2
- 18
- 43
I do not understand this yet but it is my favourite entry so far.
- 282
- 2
- 11
mogged in 15 bytes (still beats you even without ouput formatting) + ⦷
exists

- 17.3k
- 3
- 33
- 53
I wrote some basic code in PHP to do this challenge:
<?php
$json = file_get_contents("List of 1000 strings.json");
$list = json_decode($json);
$nonPangram = 0;
$normalPangram = 0;
$perfectPangram = 0;
foreach ($list as $item) {
$lowercase = strtolower($item));
$alfabet = array_intersect(str_split($lowercase), range("a", "z"));
$counts = array_count_values($alfabet);
if (count($counts) == 26) {
if (array_sum($counts) == 26) {
$perfectPangram++;
} else {
$normalPangram++;
}
} else {
$nonPangram++;
}
}
echo "This list contains $nonPangram non-pangrams, $normalPangram normal pangrams and $perfectPangram perfect pangrams.";
The output is:
This list contains 819 non-pangrams, 132 normal pangrams and 49 perfect pangrams.
I leave it to the reader to infer that there are a total of 181 pangrams, normal and perfect.
This was not a hard challenge for me, although I hope I got the answer right. I tried to look for things like accents, but didn't see them. If they are there my results would not be right, but that could be easily corrected.
The algorithm is:
Turn everything into lower case characters.
Turn the string into an array of characters, excluding everything except the [a - z] set.
Use the PHP function array_count_values to count the values.
Then evaluate the result.
I spent most of my time replacing the regular expression, I had at first, by something more PHP-like. So I used an array intersect:
$alfabet = array_intersect(str_split($lowercase), range("a", "z"));
instead of a regular expression:
$alfabet = str_split(preg_replace("/[^a-z]+/", "", $lowercase));
The reason, for me, is that I find most regular expressions inscrutable. Sure, I can use something like regex101.com and work it out, but it's always an effort. Of course, in this case the regular expression is quite simple, so it could have been used.
- 2.2k
- 2
- 25
- 51
Nice - short, clean and readable. Nice usage of built-in PHP functions!

- 49.1k
- 13
- 97
- 163
I ran out of time to submit a solution, but mine resembles yours. https://3v4l.org/m4nXG
- 8.4k
- 14
- 55
- 69
Language: Java
Output
Non Pangrams: 819
Pangrams: 181
Perfect Pangrams: 49
Simple approach
A simple approach in Java could be to count separately every pangram and perfect pangram via streams. Then, compute the number of non-pangrams by subtracting the pangram count from the size of the sentences list.
Breaking down the logic:
The pangram stream would filter for only the sentences where all alphabet letters are contained (
.allMatch(p::contains)
).The perfect pangram stream would get the first and last index of each alphabet letter within a sentence, and keep the ones where:
The indexes are greater than or equal to
0
(the letter is present in the sentence).The first and last index are equal (the letter appears only once).
String[] sentences = ...;
String[] letters = new String[26];
IntStream.range(0, 26)
.forEach(i -> letters[i] = String.valueOf((char) (i + 'a')));
long numPangrams = Arrays.stream(sentences)
.map(String::toLowerCase)
.filter(p -> Arrays.stream(letters).allMatch(p::contains))
.count();
long numPerfectPangrams = Arrays.stream(sentences)
.map(String::toLowerCase)
.filter(p -> Arrays.stream(letters).allMatch(l -> {
int firstIndex = p.indexOf(l);
int lastIndex = p.lastIndexOf(l);
return firstIndex >= 0 && firstIndex == lastIndex;
}))
.count();
System.out.println("Non Pangrams: " + (sentences.length - numPangrams));
System.out.println("Pangrams: " + numPangrams);
System.out.println("Perfect Pangrams: " + numPerfectPangrams);
Simple approach demo
Here is an online demo at https://onecompiler.com/java/43x9uqyx9
Collector approach
A more efficient approach could use a custom Collector
to iterate the list of sentences only once, and keep track of the greatest minimum number of matches of the alphabet letters within a sentence (either 1
or 2
, we don't care if a letter matches more times, that's why minimum).
Breaking down the logic:
A letter doesn't appear at all (non-pangram).
All letters are present, and at least one letter appears twice (greatestMinimumMatches = 2, regular pangram)
All letters appear only once (greatestMinimumMatches = 1, perfect pangram).
public class PangramCollector implements Collector<String, PangramCollector, PangramCollector> {
private long numNonPangrams;
private long numPangrams;
private long numPerfectPangrams;
private static final String[] letters = new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
public PangramCollector() {
numNonPangrams = 0;
numPangrams = 0;
numPerfectPangrams = 0;
}
@Override
public Supplier<PangramCollector> supplier() {
return PangramCollector::new;
}
@Override
public BiConsumer<PangramCollector, String> accumulator() {
return (PangramCollector pc, String s) -> {
int greatestMinimumMatches = 0, firstIndex;
for (String letter : letters) {
firstIndex = s.indexOf(letter);
// If the letter is not in the string,
// this is not a pangram
if (firstIndex < 0) {
pc.numNonPangrams++;
return;
}
// If the letter appears only once
// and no other letter had at least two matches,
// then the greatest minimum number of matches is 1
if (firstIndex == s.lastIndexOf(letter)
&& greatestMinimumMatches < 2) {
greatestMinimumMatches = 1;
continue;
}
// If the letter appears more than once
// or any other letter appeared more than once,
// then the greatest minimum number of matches is 2
greatestMinimumMatches = 2;
}
if (greatestMinimumMatches == 1) {
pc.numPerfectPangrams++;
}
pc.numPangrams++;
};
}
@Override
public BinaryOperator<PangramCollector> combiner() {
return (p1, p2) -> {
p1.numNonPangrams += p2.numNonPangrams;
p1.numPangrams += p2.numPangrams;
p1.numPerfectPangrams += p2.numPerfectPangrams;
return p1;
};
}
@Override
public Function<PangramCollector, PangramCollector> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Set.of();
}
public long getNumNonPangrams() {
return numNonPangrams;
}
public long getNumPangrams() {
return numPangrams;
}
public long getNumPerfectPangrams() {
return numPerfectPangrams;
}
public static void main(String[] args) {
String[] sentences = ...;
PangramCollector pc = Arrays.stream(sentences)
.map(String::toLowerCase)
.collect(new PangramCollector());
System.out.println("Non pangrams: " + pc.getNumNonPangrams());
System.out.println("Pangrams: " + pc.getNumPangrams());
System.out.println("Perfect pangrams: " + pc.getNumPerfectPangrams());
}
}
Collector approach demo
Here is an online demo at https://onecompiler.com/java/43x9vhjqh
AI usage disclosure
No AI tool has been used for this challenge.
What did I learn
I learned what a pangram and a perfect pangram are.
- 8.4k
- 14
- 55
- 69
P.S. I know that in the first approach I could have added the pangrams in a temporary list and use that to count the perfect pangrams, but I don't think that the execution-time benefits would justify the cost in terms of memory occupation (in the worst-case scenario, it would correspond to allocating a second list as big as the original one).
- 180.3k
- 26
- 277
- 326
Pangram count: 181
Perfect pangram count: 49
Language: SQL (Snowflake) :
SELECT col
,REGEXP_EXTRACT_ALL(LOWER(REGEXP_REPLACE(col,'[^a-zA-Z]')),'.{1}') AS col_letters_array
,ARRAY_SIZE(ARRAY_INTERSECTION(col_letters_array, ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'])) = 26 AS is_pangram
,is_pangram AND ARRAY_SIZE(col_letters_array) = 26 AS is_perfect_pangram
,SUM(is_pangram::INT) OVER() AS pangram_count
,SUM(is_perfect_pangram::INT) OVER() AS perfect_pangram_count
FROM tab;
Data preparation:
CREATE OR REPLACE TABLE tab(col TEXT) AS SELECT $1 FROM VALUES
($$Bright vixens jump; dozy fowl quack.$$),
($$zyra nymph, quid vex jock, fblg wt$$),
-- ...
($$Hnzz yvi viw kwriy lla.$$);
Output (first 2 rows):
COL | COL_LETTERS_ARRAY | IS_PANGRAM | IS_PERFECT_PANGRAM | PANGRAM_COUNT | PERFECT_PANGRAM_COUNT |
---|---|---|---|---|---|
Bright vixens jump; dozy fowl quack. | ["b","r","i","g","h","t","v","i","x","e","n","s","j","u","m","p","d","o","z","y","f","o","w","l","q","u","a","c","k"] | TRUE | FALSE | 181 | 49 |
zyra nymph, quid vex jock, fblg wt | ["z","y","r","a","n","y","m","p","h","q","u","i","d","v","e","x","j","o","c","k","f","b","l","g","w","t"] | FALSE | FALSE | 181 | 49 |
Interesting pointers:
- some input data contains
'
so$$
used for string literals - removal of non letter characters and split to array using built-in regexp functions
- is_pangram flag - intersection of letters array vs. English alphabet, if size of result array is 26 it means it is a pangram
- is_perfect_pangram flag - reuse is_pangram flag and check is size of letters array is 26
sum(..) over()
- for summary of entire dataset- lateral column reference - referencing expression in the next expression at the same
SELECT
level - the query can be further compacted, current form for verbosity
What was the title of that book you were reading last week?