Last active
October 4, 2022 03:25
-
-
Save tsaylor/f8c2c832785a91962d1269a80c3317be to your computer and use it in GitHub Desktop.
bulleted list data store and management functions in python and javascript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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