Skip to main content
  1. About
  2. For Teams

-COMPLETE- Code Challenge #7: Pangram checker

Created
Active
Viewed 3k times
97 entries
49

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.

97 entries

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.

Sorted by:
79784699
0

What was the title of that book you were reading last week?

79782822
2

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
79781906
0

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'

79780781
2
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
79780332
1
gimix gimix
  • 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)

79780329
1
Remy Remy
  • 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);
79782423
0

echo sprintf() is an antipattern - it is never appropriate. This is what printf() is for.

79779935
1

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.

79779815
1

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)
79778922
6

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;
79779974
1
Daniel Daniel
  • 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.

79786141
1

Nice job Jeff. @Daniel: actually Swan has a graphical representation as well

79778617
1

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;
    }
}
79778049
2
Andam Andam
  • 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
79777795
1
Output
Number of non pangrams: 819
Number of pangrams: 181
Number of pure pangrams: 49

Code Logic
  1. Use regex to remove non alphabets
  2. Create set of these letters, it will give unique alphabets in a line
  3. if the length of unique alphabets == 26 it is pangram
  4. 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)
79777551
-1

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.

79781084
0

Thanks for your submission. I think something is off with the logic. I'll try to take a look later on.

79781814
0

I think you just need to use and instead of & - see what is the difference between "&" and "and" in Python?

79781959
1

@peter-hull Thanks so much, turns out I actually am learning something from this challenge!

79777505
1

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()
79777224

This reply has been deleted.

79781086
0

Thanks for attempting the challenge. This isn't the correct answer. If I get time, I'll try to look at your logic.

79776722
-2
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)
79781087
1

Looks like a good start but missing the output counts

79776716
1

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)
            )
        )
    )
    )
)
79776663
1

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));
    }
}
79776048
1

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.

79775996
1
Daniel Daniel
  • 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.

79775979
1

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
79775951
1
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.

79775936
1

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));
79775494
1
  • 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)
79775458
1

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
  }`
);
79775288
1

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);
}
79775161
1

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.

79775089
3

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
79775019
1

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).

79775004
1

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}")

79774999
0
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
79774906
-3
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
79774839
1

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'
    )
79774810
1
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

79774773
1
Booboo Booboo
  • 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:

  1. Convert the string to lower case.
  2. Remove non-alpha characters using a regular expression.
  3. If length of the resultant string < 26, then it cannot be a pangram.
  4. Otherwise, add each character to a set.
  5. If the length of the set is not 26, then then the string cannot be a pangram.
  6. 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)
79774209
1
choroba choroba
  • 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.

79773715
1
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

79773658
1

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.

79773580
-1

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))
79773537
1

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.

79773332
1

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();
79773125
1
Grismar Grismar
  • 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.
79773039
1
JimN JimN
  • 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.

79772814
1

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    
79772700
1

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;
}



79772359
1
  • 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

79772348
2

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"
79773146
0

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.

79772252
1

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
}
79772223
1

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
79772176
1

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()} 
"""
)
79772020
1
Naeio Naeio
  • 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.

79771985
1

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;

}
79771783
1

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;
79771669
1
  • 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)}")
79771630
1

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;
    }
}
79772018
0

you have considered A and a as different character so both of them has been counted i guess

79771584
1

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 :)

79771434
2

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}
79771383
4

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.

79773666
1

I am shocked by how legible this is.

79771292
2

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=}')
79771213
1

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}")
79771185
1

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("\"")
79771137
0

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.

79771111
1

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

79771108
1
Vampire Vampire
  • 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}") }
79771082
1
Markus Markus
  • 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();

        }
79771002
1
Rawson Rawson
  • 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
79770991
1

`

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);

}
}

`

79770957
2

Explanation:

  1. For cleaner code, I have used string module for lowercase letter and punctuation string. I also used built-in str.maketrans() and str.translate() method for cleaner code. Since str.maketrans() require one to one character i have multiple " " * 10 so that each punctuation is mapped to " " only.
  2. 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]))
79770762
-2
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
    };
}
79770759
1

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")
}
79770543
1
Jim Jim
  • 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;
79770493
1

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 .

79770468
-1

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.

79770344
1

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())
79770340
1

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
79769833
1
Utopia Utopia
  • 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}")
79769514
1

Vyxal 3, 18 bytes

#?ƛʀ⦷ka∦⊍Þ⊍ɦ¬&¨¬}∑

Vyxal It Online!

#?ƛʀ⦷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]
79769524
2
lyxal lyxal
  • 1.1k
  • 2
  • 18
  • 29

Doesn't output the number of non-pangrams (not so mogged now :p)

79769548
2

fixed for 3 bytes. the mogging will continue until score improves.

79769475
-1

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
79769444
2

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)
79769411
1

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 };
79769278
1
samkart samkart
  • 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|
# +------------+--------+----------------+----------------------+
79768960
2

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
79768954
0
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

79768908
-2

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}")
79768879
0

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 using map[rune]bool. Each letter maps to a bit position, and checking for all 26 letters becomes a simple comparison with 0x3FFFFFF.

  • 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 of int 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.

79768836
2

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);
    }
}
79768761
2

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
79768752
4
depperm depperm
  • 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
  }
})
79768670
2
sehe sehe
  • 399.7k
  • 49
  • 474
  • 671

pangrams: 181, perfect pangrams: 49, others: 819

Live

#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.

79768525
3
chrslg chrslg
  • 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"

79768391
1

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]
79768348
4

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.

79768277
1

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
]
79768213
2
Amadan Amadan
  • 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
79767897
13
lyxal lyxal
  • 1.1k
  • 2
  • 18
  • 29

Vyxal 3, 46 bytes

eƛ~ɾ“ʀS:u;ka=1&1FwṪ}∑"ƛƛiṬ▲2⎇¨\ø¹∧F_:w«⎂?[⑴”$%

Vyxal It Online!

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.

79767900
1
lyxal lyxal
  • 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.

79767902
1
lyxal lyxal
  • 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.

79768842
1

I do not understand this yet but it is my favourite entry so far.

79769521
0

mogged in 15 bytes (still beats you even without ouput formatting) + exists

79767810
3

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.

79780700
0

Nice - short, clean and readable. Nice usage of built-in PHP functions!

79782446
0

I ran out of time to submit a solution, but mine resembles yours. https://3v4l.org/m4nXG

79767800
2

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.

79770293
0

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).

79767774
3

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
Morty Proxy This is a proxified and sanitized view of the page, visit original site.