Sutta Central Parallels


Extracting Parallels

On Sutta Central GitHub, we find the folowing file parallels.json:

const parallels = fetch(
  "https://raw.githubusercontent.com/suttacentral/sc-data/main/relationship/parallels.json"
).then((response) => response.json())

We can extract into a simpler array, by removing the # details and the ~ (which means ?):

const parallelsArray = parallels.map((d) =>
  d.parallels?.map((p) => p.split("#")[0].replace(/~/g, ""))
)

Sutta Pitaka Suttas

We can extract the suttapitaka leaves from the following chart:

chart

Leaves are stored in a JSON, after extracting the relevant information from root.leaves() we have the following data:

Cross Reference

We have 6725 sets of parallels and 1119 leaves. Some leaves represent individual sutta, some represent a range of sutta.

For example the leaf sn4.21–25 represent all the suttas from sn4.21 to sn4.25

We want to populate the 1119 leaves with all their parallels.

With the following function:

import fs from 'fs';
import root from '../data/leaves.json' assert { type: 'json' };
import parallels from '../data/parallels.json' assert { type: 'json' };


function addParallelItems(root, parallels) {
    // Helper function to remove duplicates from an array
    function removeDuplicates(array) {
        return [...new Set(array)];
    }

    function parseRange(rangeString) {
        // Split the string by the hyphen to separate start and end values
        const parts = rangeString.split('–'); // Note: This is an en dash, not a regular hyphen (check your input)
    
        // Extract the start and end values // ki22.3–9
        const start = parts[0];  // ki22.3
        const end = parts[1];    // 9
    
        // Check if the start value has a decimal part
        const hasDecimal = start.includes('.');
    
        // If the start value has a decimal part, append it to the end value
        if (hasDecimal) {
            const begining = start.split('.')[0]; // ki22
            return [start, begining + '.' + end];
        }
    
        // If no decimal part, return the original start and end values
        const begining = start.split(/\d/)[0]; // ki22
        return [start, begining+end];
    }

    // Loop through each item in the root array
    root.forEach((d) => {
        const item = d.facro;
        // Check if the item is a range
        if (item?.includes('–')) {
            const [start, end] = parseRange(item);
            d.range = [start, end] 
            // Loop through each parallel
            parallels.forEach(parallel => {
                // Check if any item in the parallel is within the range
                if (parallel >= start && parallel <= end) {
                    // Add the parallel items to the root item, ensuring no duplicates
                    d.parallels = removeDuplicates([...d.parallels, ...parallel]);
                }
            });
        } else {
            // If the item is not a range, directly check for its presence in parallels
            parallels?.forEach(parallel => {
                if (parallel?.includes(item)) {
                    // Add the parallel items to the root item, ensuring no duplicates
                    d.parallels = removeDuplicates([...d.parallels, ...parallel]);
                }
            });
        }
    });

    return root;
}
const updatedRoot = addParallelItems(root, parallels);

// Write the updatedRoot array to a JSON file
fs.writeFile('../data/leavesWithParallels.json', JSON.stringify(updatedRoot, null, 2), (err) => {
    if (err) throw err;
    console.log('The file has been saved!');
});


We get:

This is good, but not sufficiant yet...

We have to map the parallels with the leaf id for the one inside ranges, an, sn,

With the following code:

import fs from 'fs';
import leaves from '../data/leavesWithParallels.json' assert { type: 'json' };


function fixParallelsReference(leaves) {
    // Helper function to remove duplicates from an array
    function removeDuplicates(array) {
        return [...new Set(array)];
    }

    let lim = 0

    // Loop through each item in the root array

    leaves.forEach((d) => {
        if (true || lim < 1) {
            lim++
            d.parallelsInSuttaPtiaka = [];
            d.parallels.forEach(p => {
                let isLeaf = leaves.find(leaf => leaf.facro == p)
                if (!isLeaf) isLeaf = leaves.filter(leaf => leaf.range).find(leaf => (leaf.range[0] < p && p < leaf.range[1]))
                //console.log(isLeaf)
                if (isLeaf && isLeaf.facro != d.facro) d.parallelsInSuttaPtiaka = removeDuplicates([...d.parallelsInSuttaPtiaka, isLeaf.facro]);
                //console.log(d)
            })
        }
    });

    return leaves;
}
const updatedRoot = fixParallelsReference(leaves);

// Write the updatedRoot array to a JSON file
fs.writeFile('../data/leavesWithFixParallels.json', JSON.stringify(updatedRoot, null, 2), (err) => {
    if (err) throw err;
    console.log('The file has been saved!');
});

we have parallels that are only in our charts as leaves:

We get a result like this

chart2