Utility Function Extractor
{/* Approximate progress indicator */}{`${numSteps} out of ~${expectedSteps} (max ${maxSteps}) comparisons`}
{/* Comparison section */}/* Imports */ import Head from 'next/head' import React, { useState } from "react"; import { DrawGraph, removeOldSvg } from './labeledGraph'; import { SubmitSliderButton } from "./slider"; import { DisplayElement } from './displayElement' import { DisplayAsMarkdown } from './displayAsMarkdown' import { CreateTable, buildRows } from './findPaths' import { DataSetChanger } from "./datasetChanger" import { ComparisonsChanger } from "./comparisonsChanger" import { pushToMongo } from "./pushToMongo.js" import { increasingList, maxMergeSortSteps, expectedNumMergeSortSteps, sleep } from "./utils.js" /* DEFINTIONS */ const DEFAULT_COMPARE = () => 1 // 1/Math.random() - 1 /* Misc. helpers */ let buildLinks = quantitativeComparisons => quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({ source: element1, target: element2, distance: distance, reasoning: reasoning })) Array.prototype.containsArray = function (val) { var hash = {}; for (var i = 0; i < this.length; i++) { hash[this[i]] = i; } return hash.hasOwnProperty(val); } let checkIfListIsOrdered = (arr, binaryComparisons) => { let l = arr.length let isOrdered = true for (let i = 0; i < l - 1; i++) { isOrdered = isOrdered && binaryComparisons.containsArray([arr[i], arr[i + 1]]) } return isOrdered } let nicelyFormatLinks = (quantitativeComparisons, listOfElements) => quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({ source: listOfElements[element1].name, target: listOfElements[element2].name, distance: distance, reasoning: reasoning })) // Main react component export default function ComparisonView({ listOfElementsForView }) { /* State */ // initial state values let initialListOfElements = listOfElementsForView.map((element, i) => ({ ...element, id: i })) let initialPosList = increasingList(listOfElementsForView.length) // [0,1,2,3,4] let initialComparePair = [initialPosList[initialPosList.length - 2], initialPosList[initialPosList.length - 1]] let initialSliderValue = 1 let initialReasoning = '' let initialBinaryComparisons = [] let initialQuantitativeComparisons = [] let initialIsListOdered = false let initialOrderedList = [] let initialShowAdvancedOptions = false let initialShowComparisons = false let initialShowLoadComparisons = false let initialShowChangeDataSet = false let initialNumSteps = 0; let initialMaxSteps = maxMergeSortSteps(listOfElementsForView.length) let initialExpectedSteps = expectedNumMergeSortSteps(listOfElementsForView.length) let initialTableRows = [] let initialDontPushSubmitButtonAnyMore = false // state variables and functions const [listOfElements, setListOfElements] = useState(initialListOfElements) const [posList, setPosList] = useState(initialPosList) const [toComparePair, setToComparePair] = useState(initialComparePair) const [sliderValue, setSliderValue] = useState(initialSliderValue) const [reasoning, setReasoning] = useState(initialReasoning) const [binaryComparisons, setBinaryComparisons] = useState(initialBinaryComparisons) const [quantitativeComparisons, setQuantitativeComparisons] = useState(initialQuantitativeComparisons) // More expressive, but more laborious to search through. For the ordering step, I only manipulate the binaryComparisons. const [isListOrdered, setIsListOrdered] = useState(initialIsListOdered) const [orderedList, setOrderedList] = useState(initialOrderedList) const [dontPushSubmitButtonAnyMore, setDontPushSubmitButtonAnyMore] = useState(initialDontPushSubmitButtonAnyMore) let [showAdvancedOptions, changeShowAdvanceOptions] = useState(initialShowAdvancedOptions); let [showComparisons, changeShowComparisons] = useState(initialShowComparisons); let [showLoadComparisons, changeShowLoadComparisons] = useState(initialShowLoadComparisons); let [showChangeDataSet, changeshowChangeDataSet] = useState(initialShowChangeDataSet); let [numSteps, changeNumSteps] = useState(initialNumSteps); let [maxSteps, changeMaxSteps] = useState(initialMaxSteps) let [expectedSteps, changeExpectedSteps] = useState(initialExpectedSteps) let [tableRows, setTableRows] = useState(initialTableRows) /* Convenience utils: restart + changeDataSet */ let restart = (posList, initialBinaryComparisons2, initialQuantitativeComparisons2) => {//({posList, initialBinaryComparisons2, initialQuantitativeComparisons2}) => { setToComparePair([posList[posList.length - 2], posList[posList.length - 1]]) setSliderValue(initialSliderValue) setBinaryComparisons(initialBinaryComparisons2 || initialBinaryComparisons) setQuantitativeComparisons(initialQuantitativeComparisons2 || initialQuantitativeComparisons) setIsListOrdered(initialIsListOdered) setOrderedList(initialOrderedList) changeNumSteps(initialNumSteps) removeOldSvg() setTableRows(initialTableRows) setDontPushSubmitButtonAnyMore(initialDontPushSubmitButtonAnyMore) } let changeDataSet = (listOfElementsNew) => { listOfElementsNew = listOfElementsNew.map((element, i) => ({ ...element, id: i })) let newPosList = increasingList(listOfElementsNew.length) let newListLength = listOfElementsNew.length setListOfElements(listOfElementsNew) setPosList(increasingList(listOfElementsNew.length)) setToComparePair([newPosList[newPosList.length - 2], newPosList[newPosList.length - 1]]) changeExpectedSteps(expectedNumMergeSortSteps(newListLength)) changeMaxSteps(maxMergeSortSteps(newListLength)) restart(newPosList) // restart({posList: newPosList}) } let changeComparisons = async (links) => { let quantitativeComparisons2 = [] let binaryComparisons2 = [] links.shift() for (let link of links) { let { source, target, distance, reasoning } = link let searchByName = (name, candidate) => candidate.name == name let testForSource = (candidate) => searchByName(source, candidate) let testForTarget = (candidate) => searchByName(target, candidate) let element1 = listOfElements.findIndex(testForSource) let element2 = listOfElements.findIndex(testForTarget) if (element1 == -1 || element2 == -1) { console.log("link", link) console.log(source) console.log(target) throw new Error("Comparisons include unknown elements, please retry") } quantitativeComparisons2.push([element1, element2, distance, reasoning]) binaryComparisons2.push([element1, element2]) } // return ({quantitativeComparisons: quantitativeComparisons2, binaryComparisons: binaryComparisons2}) //restart({posList, initialBinaryComparisons2=initialBinaryComparisons, initialQuantitativeComparisons2=initialQuantitativeComparisons}) // restart(posList, binaryComparisons2, quantitativeComparisons2) setQuantitativeComparisons(quantitativeComparisons2) setBinaryComparisons(binaryComparisons2) } // Manipulations let compareTwoElements = (newBinaryComparisons, element1, element2) => { let element1Greater = newBinaryComparisons.containsArray([element1, element2]) let element2Greater = newBinaryComparisons.containsArray([element2, element1]) if (element1Greater || element2Greater) { return element1Greater && !element2Greater } else { setToComparePair([element1, element2]) //console.log(`No comparison found between ${element1} and ${element2}`) //console.log(`Comparisons:`) //console.log(JSON.stringify(newBinaryComparisons, null, 4)); return "No comparison found" } } function merge(newBinaryComparisons, left, right) { let sortedArr = []; // the sorted elements will go here while (left.length && right.length) { // insert the biggest element to the sortedArr let comparison = compareTwoElements(newBinaryComparisons, left[0], right[0]) if (comparison == "No comparison found") { return "No comparison found; unable to proceed" } else if (comparison) { // left[0] > right[0] sortedArr.push(left.shift()); } else { sortedArr.push(right.shift()); } } // use spread operator and create a new array, combining the three arrays return [...sortedArr, ...left, ...right]; // if they don't have the same size, the remaining ones will be greater than the ones before } function mergeSort({ array, comparisons }) { if (array == "No comparison found; unable to proceed") { return "No comparison found; unable to proceed" } const half = array.length / 2; // the base case is array length <=1 if (array.length <= 1) { return array; } const left = array.slice(0, half); // the first half of the array const right = array.slice(half, array.length) // Note that splice is destructive. let orderedFirstHalf = mergeSort({ array: left, comparisons }) let orderedSecondHalf = mergeSort({ array: right, comparisons }) if (orderedFirstHalf != "No comparison found; unable to proceed" && orderedSecondHalf != "No comparison found; unable to proceed") { let result = merge(comparisons, orderedFirstHalf, orderedSecondHalf); return result } else { return "No comparison found; unable to proceed" } } let nextStepSimple = (posList, binaryComparisons, element1, element2) => { //console.log("Binary comparisons: ") //console.log(JSON.stringify(binaryComparisons, null, 4)); let newComparison = [element1, element2] // [element1, element2] let newBinaryComparisons = [...binaryComparisons, newComparison] //console.log("New binaryComparisons: ") //console.log(JSON.stringify(newBinaryComparisons, null, 4)); setBinaryComparisons(newBinaryComparisons) let result = mergeSort({ array: posList, comparisons: newBinaryComparisons }) //console.log(result) if (result != "No comparison found; unable to proceed" && checkIfListIsOrdered(result, newBinaryComparisons)) { // console.log(`isListOrdered: ${isListOrdered}`) console.log("poslist@nextStepSimple") console.log(posList) console.log("result@nextStepSimple") console.log(result) return [true, result] } else { return [false, result] } } let nextStepSlider = async ({ posList, binaryComparisons, sliderValue, reasoning, element1, element2 }) => { if (!dontPushSubmitButtonAnyMore) { if (sliderValue < 1 && sliderValue > 0) { sliderValue = 1 / sliderValue; [element1, element2] = [element2, element1] } console.log(`posList@nextStepSlider:`) console.log(posList) let [successStatus, result] = nextStepSimple(posList, binaryComparisons, element1, element2) let newQuantitativeComparison = [element1, element2, sliderValue, reasoning] let newQuantitativeComparisons = [...quantitativeComparisons, newQuantitativeComparison] setQuantitativeComparisons(newQuantitativeComparisons) setSliderValue(DEFAULT_COMPARE()) setReasoning('') changeNumSteps(numSteps + 1) if (successStatus) { setDontPushSubmitButtonAnyMore(true) let jsObject = nicelyFormatLinks(quantitativeComparisons, listOfElements) await pushToMongo(jsObject) console.log(jsObject) alert("Comparisons completed. Background work might take a while, or straight-out fail") setIsListOrdered(true) setOrderedList(result) await buildRows({ isListOrdered: true, orderedList: result, listOfElements, links: buildLinks(newQuantitativeComparisons), rows: tableRows, setTableRows }) /* setTimeout(async () => { // Make sure to do this after the }, 100); */ } } } // Html return (
{`${numSteps} out of ~${expectedSteps} (max ${maxSteps}) comparisons`}
{/* Comparison section */}