Skip to content

Instantly share code, notes, and snippets.

@tsaylor
Last active October 4, 2022 03:25
Show Gist options
  • Save tsaylor/f8c2c832785a91962d1269a80c3317be to your computer and use it in GitHub Desktop.
Save tsaylor/f8c2c832785a91962d1269a80c3317be to your computer and use it in GitHub Desktop.
bulleted list data store and management functions in python and javascript
var BulletList = function() {
return {
data: [],
get_by_id: function(id, data) {
items = data.filter(d => d.id == id)
return items?items[0]:null
},
get_by_prev_sibling_id: function(id, data) {
items = data.filter(d => d.prev_sibling == id)
return items?items[0]:null
},
order_children: function(children) {
if (children.length < 2) {
return children
}
let prev_sibling_id = null
let ordered_children = []
do {
let next_child = children.filter(child => child.prev_sibling == prev_sibling_id)
if (next_child.length) {
next_child = next_child.pop()
prev_sibling_id = next_child.id
ordered_children.push(next_child)
}
} while (ordered_children.length != children.length);
return ordered_children
},
indent: function(id, data) {
let item = this.get_by_id(id, data)
if (item.prev_sibling == null) {
return false
}
let prev_sibling = this.get_by_id(item.prev_sibling, data)
let next_sibling = this.get_by_prev_sibling_id(id, data)
let children = data.filter(d => d.parent == prev_sibling.id)
let last_child_id = (children.length > 0)?this.order_children(children).pop().id:null
item.parent = prev_sibling.id
item.prev_sibling = last_child_id
if (next_sibling) {
next_sibling.prev_sibling = prev_sibling.id
}
},
dedent: function(id, data) {
let item = this.get_by_id(id, data)
if (item.parent == null) {
return false
}
let old_sibling = this.get_by_prev_sibling_id(id, data)
if (old_sibling) {
old_sibling.parent = item.id
old_sibling.prev_sibling = null
}
let parent = this.get_by_id(item.parent, data)
let next_sibling = this.get_by_prev_sibling_id(parent.id, data)
if (next_sibling) {
next_sibling.prev_sibling = item.id
}
item.prev_sibling = parent.id
item.parent = parent.parent
},
get_subtree: function(parent_id, data) {
let final_list = []
let children_of_item = this.order_children(data.filter(d => d.parent == parent_id))
for (const item of children_of_item) {
final_list.push(item.value)
let subtree = this.get_subtree(item.id, data)
if (subtree.length > 0) {
final_list.push(subtree)
}
}
return final_list
},
}
}
// Test
//
// let data = [
// {'id': 1, 'value': 'a', 'parent': null, 'prev_sibling': null},
// {'id': 2, 'value': 'b', 'parent': null, 'prev_sibling': 1},
// {'id': 3, 'value': 'c', 'parent': null, 'prev_sibling': 2},
// {'id': 4, 'value': 'd', 'parent': null, 'prev_sibling': 3},
// {'id': 5, 'value': 'e', 'parent': null, 'prev_sibling': 4},
// {'id': 6, 'value': 'f', 'parent': null, 'prev_sibling': 5},
// {'id': 7, 'value': 'g', 'parent': null, 'prev_sibling': 6}
// ]
//
// let bl = new BulletList()
// bl.data = data
//
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
// bl.indent(4, bl.data)
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
// bl.indent(5, bl.data)
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
// bl.indent(2, bl.data)
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
// bl.indent(5, bl.data)
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
// bl.dedent(5, bl.data)
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
// bl.dedent(5, bl.data)
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
// bl.dedent(4, bl.data)
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
// bl.dedent(2, bl.data)
// console.log(bl.data)
// console.log(bl.get_subtree(null, bl.data))
"""
I wanted to build something like this in javascript, this was
to nail down the logic in a more familiar language.
"""
from pprint import pprint
data = [
{'id': 1, 'value': 'a', 'parent': None, 'prev_sibling': None},
{'id': 2, 'value': 'b', 'parent': None, 'prev_sibling': 1},
{'id': 3, 'value': 'c', 'parent': None, 'prev_sibling': 2},
{'id': 4, 'value': 'd', 'parent': None, 'prev_sibling': 3},
{'id': 5, 'value': 'e', 'parent': None, 'prev_sibling': 4},
{'id': 6, 'value': 'f', 'parent': None, 'prev_sibling': 5},
{'id': 7, 'value': 'g', 'parent': None, 'prev_sibling': 6}
]
def get_by_id(id, data):
items = [d for d in data if d['id'] == id]
if len(items) > 0:
return items[0]
else:
return None
def get_by_prev_sibling_id(id, data):
items = [d for d in data if d['prev_sibling'] == id]
if len(items) > 0:
return items[0]
else:
return None
def indent(id, data):
item = get_by_id(id, data)
if item['prev_sibling'] is None:
return False
prev_sibling = get_by_id(item['prev_sibling'], data)
next_sibling = get_by_prev_sibling_id(id, data)
children = [d for d in data if d['parent'] == prev_sibling['id']]
last_child_candidate = {'id': None}
new_last_child_candidate = [c for c in children if c['prev_sibling'] is last_child_candidate['id']]
while len(new_last_child_candidate) > 0:
last_child_candidate = new_last_child_candidate[0]
new_last_child_candidate = [c for c in children if c['prev_sibling'] is last_child_candidate['id']]
item['parent'] = prev_sibling['id']
item['prev_sibling'] = last_child_candidate['id']
if next_sibling:
next_sibling['prev_sibling'] = prev_sibling['id']
def dedent(id, data):
item = get_by_id(id, data)
if item['parent'] is None:
return False
# old siblings become children
old_sibling = get_by_prev_sibling_id(item['id'], data)
if old_sibling:
old_sibling['parent'] = item['id']
old_sibling['prev_sibling'] = None
# parent becomes prev sibling
parent = get_by_id(item['parent'], data)
# old next sibling of parent becomes next sibling of item
next_sibling = get_by_prev_sibling_id(parent['id'], data)
if next_sibling:
next_sibling['prev_sibling'] = item['id']
item['prev_sibling'] = parent['id']
item['parent'] = parent['parent']
def order_children(children):
if len(children) < 2:
return children
ordered_children = [c for c in children if c['prev_sibling'] is None]
while len(children) != len(ordered_children):
next_child = [c for c in children if c['prev_sibling'] is ordered_children[-1]['id']]
if len(next_child) > 0:
ordered_children.append(next_child[0])
return ordered_children
def get_subtree(parent_id, data):
final_list = []
children_of_item = order_children([d for d in data if d['parent'] is parent_id])
for item in children_of_item:
final_list.append(item['value'])
subtree = get_subtree(item['id'], data)
if len(subtree) > 0:
final_list.append(subtree)
return final_list
pprint(data)
pprint(get_subtree(None, data))
indent(4, data)
pprint(data)
pprint(get_subtree(None, data))
indent(5, data)
pprint(data)
pprint(get_subtree(None, data))
indent(2, data)
pprint(data)
pprint(get_subtree(None, data))
indent(5, data)
pprint(data)
pprint(get_subtree(None, data))
dedent(5, data)
pprint(data)
pprint(get_subtree(None, data))
dedent(5, data)
pprint(data)
pprint(get_subtree(None, data))
dedent(4, data)
pprint(data)
pprint(get_subtree(None, data))
dedent(2, data)
pprint(data)
pprint(get_subtree(None, data))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment