By Dark PhaZe Go To PostGot some Android programming experience recently. It's….ok? I can't say I love using emulators. Are you guys pretty experienced with making native mobile apps in general? Just for curiosities sake.I haven't done any native Android apps in quite a while. I have used Xamarin for it and iOS a couple times in the last few years. I mostly dislike having to design an app for a million different layouts when it comes to Android.
Completely unrelated–Windows is becoming pretty tiresome in general. Considering dual booting to Linux and creating separation between professional stuff and gaming.
Before going to all the work of dual booting your system, enable WSL and install Debian. It will let you run a Linux environment (Debian, in this case) inside Windows without having to create VMs or anything. The WSL instance also allows you access to most directories on your Windows machine so you don't even have to redownload files you are already working with.
By Dark PhaZe Go To PostGot some Android programming experience recently. It's….ok? I can't say I love using emulators. Are you guys pretty experienced with making native mobile apps in general? Just for curiosities sake.I've built Android apps with Java and iOS apps with Swift UI, I definitely prefer Apple's APIs.
Completely unrelated–Windows is becoming pretty tiresome in general. Considering dual booting to Linux and creating separation between professional stuff and gaming.
By Dark PhaZe Go To PostGot some Android programming experience recently. It's….ok? I can't say I love using emulators. Are you guys pretty experienced with making native mobile apps in general? Just for curiosities sake.Emulators are a giant pain in the ass and use up a ton of resources. I'm not a fan of Java myself. I'd say the barrier of entry having to learn Gradle and setting all that up is pretty high and annoying.
By JesalR Go To PostI've built Android apps with Java and iOS apps with Swift UI, I definitely prefer Apple's APIs.Yea it's a much better ecosystem. The barrier of entry is much lower and Swift is a really good language.
Honestly, almost all build tooling sucks. Even React native forces you into platform specific tooling for anything with even light complexity.
It feels like something you eventually "get", but I'll never enjoy looking at Gradle, Bazel or anything else like it
It feels like something you eventually "get", but I'll never enjoy looking at Gradle, Bazel or anything else like it
By Kibner Go To PostOther than having to own or rent a Mac to compile your code. :vWouldn't want to be caught dead writing code on Windows anyhow
By JesalR Go To PostHonestly, almost all build tooling sucks. Even React native forces you into platform specific tooling for anything with even light complexity.Oh, for sure, but Gradle is just mindbogglingly confusing. Have you ever tried setting up different build flavors? Fucking atrocious.
It feels like something you eventually "get", but I'll never enjoy looking at Gradle, Bazel or anything else like it
By reilo Go To PostOh, for sure, but Gradle is just mindbogglingly confusing. Have you ever tried setting up different build flavors? Fucking atrocious.Oh, it is immensely frustrating. I built a whitesource streaming app for Android TV, and getting each release built and released was a fucking nightmare
By JesalR Go To PostNot quite. Whatever you type is being converted to a lowercase version, that lowercase version is then checked against "y"Aight. Appreciate it.
Since not both versions are being compared (the original and lowercase), the following will always `break` regardless of what you enter
while True:
print("Continue? Y/N")
response = input()
if response.lower() != "Y":
break
If your response is "Y", it gets converted to "y" and "y" != "Y" so it will hit the break
Every time I run an Android emulator Java kicks in and eats up 3GB of my RAM. Every time I close said emulator, the Java process does not stop and it does not de-allocate my RAM and I have to force kill Java.
My MBP feels like its on the brink of dying every time I run an emulator.
In other words, fuck Java.
My MBP feels like its on the brink of dying every time I run an emulator.
In other words, fuck Java.
See if you can run it on a server version of the runtime. The startup is longer but it is supposed to be easier on memory if my memories from a decade ago hold up.
But, yes, the Java runtime does suck. I don't remember if the is a way to force garbage collection to clean itself up.
But, yes, the Java runtime does suck. I don't remember if the is a way to force garbage collection to clean itself up.
Does anyone have a recommendation on a product to embed an Instagram feed (not just a single post)?
What about a YouTube channel embed?
I have found official ones for Twitter and Facebook the two above are eluding me. There seem to be a million companies that offer that service, but they all seem to strike me as sleazy so I would like some other people's opinions.
What about a YouTube channel embed?
I have found official ones for Twitter and Facebook the two above are eluding me. There seem to be a million companies that offer that service, but they all seem to strike me as sleazy so I would like some other people's opinions.
Has anyone had to group a bunch of filepaths by directory and iterate through them before? I am trying to figure out a way to do that in order to programmatically build a nested navigation element.
Have not but I imagine using a RegEx filter is your best bet. Are you using a bash script? Python?
RegEx on the first path, group that as the parent key, then make a linked list traversing down?
RegEx on the first path, group that as the parent key, then make a linked list traversing down?
By reilo Go To PostHave not but I imagine using a RegEx filter is your best bet. Are you using a bash script? Python?Using Javascript. The data is coming from a graphql query. Been trying out a couple different approaches this morning but taking a break right now.
RegEx on the first path, group that as the parent key, then make a linked list traversing down?
I figured it out but did it pretty differently. The GraphQL query returns an object for each page. One of the properties is the slug. Guaranteed unique and can also sort on it to get the order I want.
I sorted the collection of page objects by the slug and created a new property for each one that is the slug split by the directory separator ("/").
I then iterated through this sorted page object collection to create a new page object collection with grouped nodes based off parent directory. I did that by pushing each root-level node to the new collection. If the node I was looking at wasn't root level, then I looked at the existing nodes in this new collection to find which node it should be added to.
It appears to work.
I sorted the collection of page objects by the slug and created a new property for each one that is the slug split by the directory separator ("/").
I then iterated through this sorted page object collection to create a new page object collection with grouped nodes based off parent directory. I did that by pushing each root-level node to the new collection. If the node I was looking at wasn't root level, then I looked at the existing nodes in this new collection to find which node it should be added to.
It appears to work.
Yup, got sorting and grouping working all fine and dandy. Now I just have to figure out what is causing the ripple animation when clicking a link to stop animating while the next page is being loaded. I'm sure I did something wrong.
Using react, btw.
Using react, btw.
By Kibner Go To PostI figured it out but did it pretty differently. The GraphQL query returns an object for each page. One of the properties is the slug. Guaranteed unique and can also sort on it to get the order I want.So, a linked list :P
I sorted the collection of page objects by the slug and created a new property for each one that is the slug split by the directory separator ("/").
I then iterated through this sorted page object collection to create a new page object collection with grouped nodes based off parent directory. I did that by pushing each root-level node to the new collection. If the node I was looking at wasn't root level, then I looked at the existing nodes in this new collection to find which node it should be added to.
It appears to work.
By reilo Go To PostSo, a linked list :PLook at you and your proper terminology and shit. Lol
Figured I should show my work so here we go. The entry point is at the bottom with:
If you want syntax highlighting, here is a pastebin: https://pastebin.com/ej3XZmM4
const nodes = getGroupedNodes(data.allMarkdownRemark.edges)
If you want syntax highlighting, here is a pastebin: https://pastebin.com/ej3XZmM4
import React from "react"
import { graphql, useStaticQuery } from "gatsby"
// populates nodes with an array filled with each directory in slug
const populateNodeDirectories = edges => {
return edges.map(({ node }) => {
node.directories = node.fields.slug
.split("/")
.filter(element => element.length > 0)
return node
})
}
const arraysEqual = (a, b) => {
if (a === b) return true
if (a == null || b == null) return false
if (a.length !== b.length) return false
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false
}
return true
}
// determines order of slugs such that parents come before children
const compareSlugs = (a, b) => {
const minDirCount = Math.min(a.directories.length, b.directories.length)
for (let i = 0; i < minDirCount; i++) {
if (a.directories[i] < b.directories[i]) {
return -1
}
if (a.directories[i] > b.directories[i]) {
return 1
}
}
return a.directories.length - b.directories.length
}
// Determines order of nodes for display. display_order is nullable and has
// higher priority over title
const compareDisplayOrder = (a, b) => {
const a_displayOrder = a.frontmatter.display_order
const b_displayOrder = b.frontmatter.display_order
if (a_displayOrder === b_displayOrder) {
const a_title = a.frontmatter.title
const b_title = b.frontmatter.title
if (a_title > b_title) {
return 1
}
if (a_title < b_title) {
return -1
}
}
if (a_displayOrder === null) {
return 1
}
if (b_displayOrder === null) {
return -1
}
if (a_displayOrder > b_displayOrder) {
return 1
}
if (a_displayOrder < b_displayOrder) {
return -1
}
return 0
}
const findParentNode = (nodes, childNode) => {
const parentNode = nodes.find(node => {
return isParentNode(node, childNode)
})
if (parentNode) {
return parentNode
} else {
// iterates through each node on current level and recursively runs for all
// children on those nodes until a parent node is found
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].children instanceof Array) {
return findParentNode(nodes[i].children, childNode)
}
}
}
}
const isParentNode = (parentNode, childNode) => {
return arraysEqual(
parentNode.directories,
childNode.directories.slice(0, childNode.directories.length - 1)
)
}
const groupNodes = nodes => {
// requires nodes to be sorted by slug to work correctly
nodes.sort(compareSlugs)
let groupedNodes = []
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].directories.length === 0) {
// skip home index node
} else if (nodes[i].directories.length === 1) {
// add root level nodes
nodes[i].children = []
groupedNodes.push(nodes[i])
} else {
// find parent node for current node and add it as a child
const parentNode = findParentNode(groupedNodes, nodes[i])
if (parentNode) {
nodes[i].children = []
parentNode.children.push(nodes[i])
}
}
}
return groupedNodes
}
const sortNodesByDisplayOrder = nodes => {
nodes.sort(compareDisplayOrder)
for (let i = 0; i < nodes.length; i++) {
// iterates through each node on current level and recursively runs for all
// children on those nodes until each node and all their children are sorted
if (nodes[i].children instanceof Array) {
sortNodesByDisplayOrder(nodes[i].children)
}
}
return nodes
}
const getGroupedNodes = edges => {
let nodes = populateNodeDirectories(edges)
nodes = groupNodes(nodes)
nodes = sortNodesByDisplayOrder(nodes)
return nodes
}
const NavigationDrawer = () => {
const data = useStaticQuery(graphql`
query {
allMarkdownRemark {
edges {
node {
id
frontmatter {
title
display_order
}
fields {
slug
}
}
}
}
}
`)
const nodes = getGroupedNodes(data.allMarkdownRemark.edges)
{...}
}
If anyone wants a challenge, they can try to figure out how to convert the recursion in functions findParentNode and sortNodesByDisplayOrder to an iterative equivalent.
If you do, please let me know what you come up with 😅
If you do, please let me know what you come up with 😅
Sooo when I talked about making it into a linked list, I was suggesting that when you do the initial split you remap it to tag the ancestor (parent) and descendant (child) notes. If you do that initially your recursion algorithm to find the parent from a child becomes much easier.
Your solution works but it's a bit brute force with a lot of recursion. Converting the directories into a tree initially opens up many more simpler and efficient methods for you to go through the structure.
Your solution works but it's a bit brute force with a lot of recursion. Converting the directories into a tree initially opens up many more simpler and efficient methods for you to go through the structure.
By reilo Go To PostSooo when I talked about making it into a linked list, I was suggesting that when you do the initial split you remap it to tag the ancestor (parent) and descendant (child) notes. If you do that initially your recursion algorithm to find the parent from a child becomes much easier.Gotcha. Thanks! I will try to do that later today after I fix up a different issue. And, yeah, I didn't exactly like how I was doing things and knew something was wrong. But I get that feeling basically every time I use recursion. Always feel like "there has to be a better way".
Your solution works but it's a bit brute force with a lot of recursion. Converting the directories into a tree initially opens up many more simpler and efficient methods for you to go through the structure.
Also, for anyone looking for a static site host, Vercel was quick and easy to get going for me. Free for personal projects with not obvious limitations listed on their website. Offers continuous integration with github, gitlabs, and one other source control site. Also lets you setup staging and testing environments with other branches.
By reilo Go To PostShould've used FirebaseQuite possibly! Easy enough to change.
@reilo
I changed how the navigation tree was created to be less brute force. https://pastebin.com/Naq5Lk9d
Another friend showed me a way my old sorting could be done to remove recursion, so I may try and take a stab at that, as well.
I changed how the navigation tree was created to be less brute force. https://pastebin.com/Naq5Lk9d
// Determines order of nodes for display. display_order is nullable and has
// higher priority over title
const compareDisplayOrder = (a, b) => {
if (a.display_order === b.display_order) {
if (a.title > b.title) {
return 1
}
if (a.title < b.title) {
return -1
}
}
if (a.display_order === null) {
return 1
}
if (b.display_order === null) {
return -1
}
if (a.display_order > b.display_order) {
return 1
}
if (a.display_order < b.display_order) {
return -1
}
return 0
}
const buildNavigationTree = edges => {
const navigationTree = {}
let currentBranch
for (const edge of edges) {
currentBranch = navigationTree
// create tree based off each directory segment in slug for each node
for (const slugSegment of edge.node.fields.slug.split("/")) {
if (slugSegment !== "") {
if (!currentBranch.children) {
currentBranch.children = {}
}
// if currentBranch.children does not have a property of the same name
// of slugSegment, then we need to create a new branch for this
// slugSegment
if (!(slugSegment in currentBranch.children)) {
currentBranch.children[slugSegment] = {}
currentBranch.children[slugSegment].id = edge.node.id
currentBranch.children[slugSegment].slug = edge.node.fields.slug
currentBranch.children[slugSegment].title =
edge.node.frontmatter.title
currentBranch.children[slugSegment].display_order =
edge.node.frontmatter.display_order
}
// change currentBranch to the new branch we just created
currentBranch = currentBranch.children[slugSegment]
}
}
}
// remove root-level children property as it is unnecessary
return navigationTree.children
}
const sortNavigationTree = navigationTree => {
let sortedTree = Object.keys(navigationTree)
.sort((a, b) => compareDisplayOrder(navigationTree[a], navigationTree[b]))
// use the sort results to reorder the properties on the current branch
.reduce(function (result, key) {
result[key] = navigationTree[key]
return result
}, {})
for (const node in sortedTree) {
// iterates through each node on current level and recursively runs for all
// children on those nodes until each node and all their children are sorted
if (sortedTree[node].children) {
sortedTree[node].children = sortNavigationTree(sortedTree[node].children)
}
}
return sortedTree
}
const data = useStaticQuery(graphql`
query {
allMarkdownRemark {
edges {
node {
id
frontmatter {
title
display_order
}
fields {
slug
}
}
}
}
}
`)
let navigationTree = buildNavigationTree(data.allMarkdownRemark.edges)
navigationTree = sortNavigationTree(navigationTree)
Another friend showed me a way my old sorting could be done to remove recursion, so I may try and take a stab at that, as well.
By reilo Go To PostFirst pass and that looks pretty good! I'll have to check it properly later.I need to change it to build arrays of objects instead of objects all the way down, I think. If I can figure that out, I can use the Array.map function inside the normal React render call. It would also let me use a real push/pop to get rid of recursion in the sort.
I figured out how to return as an array: https://pastebin.com/L6jRGSrS
Much easier to work with in this form, tbh.
// Determines order of nodes for display. display_order is nullable and has
// higher priority over title
const compareDisplayOrder = (a, b) => {
const a_displayOrder = a.frontmatter.display_order
const b_displayOrder = b.frontmatter.display_order
if (a_displayOrder === b_displayOrder) {
const a_title = a.frontmatter.title
const b_title = b.frontmatter.title
if (a_title > b_title) {
return 1
}
if (a_title < b_title) {
return -1
}
}
if (a_displayOrder === null) {
return 1
}
if (b_displayOrder === null) {
return -1
}
if (a_displayOrder > b_displayOrder) {
return 1
}
if (a_displayOrder < b_displayOrder) {
return -1
}
return 0
}
const buildNavigationTree = edges => {
const navigationTree = {}
let currentBranch
for (const edge of edges) {
// resets to top of tree
currentBranch = navigationTree
// create tree based off each directory segment in slug for each node
for (const slugSegment of edge.node.fields.slug.split("/")) {
if (slugSegment !== "") {
if (!currentBranch.children) {
currentBranch.children = []
}
let currentBranchChildIndexForSlugSegment = currentBranch.children.findIndex(
child => child.slugSegment === slugSegment
)
// if currentBranch does not have a child matching the current
// slugSegment, create a new branch
if (currentBranchChildIndexForSlugSegment === -1) {
edge.node.slugSegment = slugSegment
currentBranch.children.push(edge.node)
currentBranchChildIndexForSlugSegment = currentBranch.children.length - 1
}
// change currentBranch to the branch we either just found or created
currentBranch = currentBranch.children[currentBranchChildIndexForSlugSegment]
}
}
}
// remove root-level children property as it is unnecessary
return navigationTree.children
}
const sortNavigationTree = navigationTree => {
navigationTree.sort(compareDisplayOrder)
for (let i = 0; i < navigationTree.length; i++) {
// iterates through each node on current level and recursively runs for all
// children on those nodes until each node and all their children are sorted
if (navigationTree[i].children instanceof Array) {
sortNavigationTree(navigationTree[i].children)
}
}
return navigationTree
}
const data = useStaticQuery(graphql`
query {
allMarkdownRemark {
edges {
node {
id
frontmatter {
title
display_order
}
fields {
slug
}
}
}
}
}
`)
let navigationTree = buildNavigationTree(data.allMarkdownRemark.edges)
navigationTree = sortNavigationTree(navigationTree)
Much easier to work with in this form, tbh.
A friend gave me some C code that should be replicatable in javascript that builds a tree from filepaths: https://gcc.godbolt.org/z/hr3o1v
Unfortunately, I just have not been able to translate it, yet. The biggest advantage I can see it has over my current implementation is that it does not need to do a find for existing nodes in the tree. I am sure I can do a similar thing with my code, but my brain is just not having it right now.
Unfortunately, I just have not been able to translate it, yet. The biggest advantage I can see it has over my current implementation is that it does not need to do a find for existing nodes in the tree. I am sure I can do a similar thing with my code, but my brain is just not having it right now.
I was able to convert this little project from using MD files for content pages to using MDX files. This will allow for using React components inside the markdown code and possibly other features that will make creating the content pages easier and keep them more consistently styled.
By reilo Go To PostReally. Can you link me to that? I didn't know that was possible and it will be super useful.The generic react version: https://github.com/mdx-js/mdx
The plugin for Gatsby I am using: https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-mdx
- and a tutorial for it: https://www.gatsbyjs.com/docs/mdx/getting-started/
Fine tuned the navigation tree creation function even more. I think I can call it done because I am not sure if there are any other significant performance or stylistic/legibility gains to be made.
I also remembered that I can sort queries with GraphQL. So, I did that and now I no longer need a sorting function in the navigation component since the function above respects the order the data comes in! Between my initial brute force version and this, I was able to remove like 100 lines of code and still have things be quicker and easier to read.
e: also, i wish i could take credit for coming up with that solution, but i found it as the accepted answer in this stackoverflow question: https://stackoverflow.com/questions/57344694/create-a-tree-from-a-list-of-strings-containing-paths-of-files-javascript
const buildNavigationTree = edges => {
const result = []
const level = { result }
edges.forEach(edge => {
edge.node.fields.slug
.split("/")
.filter(splitValue => splitValue !== "")
.reduce((accumulator, currentValue) => {
if (accumulator[currentValue]) {
// current entry is already in accumulator so do nothing
} else {
accumulator[currentValue] = { result: [] }
accumulator.result.push({
children: accumulator[currentValue].result,
id: edge.node.id,
title: edge.node.frontmatter.title,
slug: edge.node.fields.slug,
})
}
return accumulator[currentValue]
}, level)
})
return result
}
I also remembered that I can sort queries with GraphQL. So, I did that and now I no longer need a sorting function in the navigation component since the function above respects the order the data comes in! Between my initial brute force version and this, I was able to remove like 100 lines of code and still have things be quicker and easier to read.
e: also, i wish i could take credit for coming up with that solution, but i found it as the accepted answer in this stackoverflow question: https://stackoverflow.com/questions/57344694/create-a-tree-from-a-list-of-strings-containing-paths-of-files-javascript
You used a reduce, I'm so proud of you 😭
That's a mighty proper solution. Glad you went through the process yourself because that's a natural progression of how to solve that problem.
EDIT: Godammit Kibner just read your edit I am so disappointed
That's a mighty proper solution. Glad you went through the process yourself because that's a natural progression of how to solve that problem.
EDIT: Godammit Kibner just read your edit I am so disappointed
lmao
well, i am going through it now and seeing if i can remove that "filter" function and somehow inline it into the reduce to prevent extra traversals, but that is proving troublesome, so far
well, i am going through it now and seeing if i can remove that "filter" function and somehow inline it into the reduce to prevent extra traversals, but that is proving troublesome, so far
By reilo Go To PostYou can pass in a Regular Expression into the split that accounts for the empty string result.I did it with a simple IF statement inside the reducer function, instead. Just checks to see if the currentValue is an empty string and returns the accumulator if it does.
However, working on this showed me that this tree creation function requires parent nodes to be processed before child nodes, so I had to add back in some of my sorting code. However, I only run the sort function when a level is being rendered instead of for the whole tree like I did before. Not sure if it will really make a difference, but whatever.
Realized that the plug-ins I'm using for markdown stuff also keeps track of headings and their auto generated id's. I can use this information to automatically build tables of contents for each page.
Yay, automate all the things!
Yay, automate all the things!
Added automatic generation of tables of contents and breadcrumb bar as well as a (hopefully) permanent fix for anchor tag scrolling with a fixed height header: https://sw-eote-srd.vercel.app/playing-the-game/the-dice/
That makes the framework of the site complete, imo, unless anyone has some suggestions. Everything else will be related to displaying content how the user wants, like the different dice symbols this game system uses.
That makes the framework of the site complete, imo, unless anyone has some suggestions. Everything else will be related to displaying content how the user wants, like the different dice symbols this game system uses.
And my gf came through in the clutch and was able to generate some svg images for the icons I needed. I was able to put them in components and added it to the shortcode list and they can now be used in .mdx files without importing anything by just typing
<iconname/>
where "IconName" is whatever the name of the icon is.
I am working on the next step for this documentation website I have been working on in my spare time (https://github.com/kibner/mdx-documentation-site): search.
Since this is a static site generator, I need to use or create a service to do the searching for me. Otherwise, the user would need to download the text of every page in the site when they use search.
I started looking at a bunch of different engines and decided on Algolia. It is unique, from what I can tell, in that it doesn't index your site via a site crawler. Instead, you create JSON objects of all your possible search records and send it to their servers. Then, when you call their search service, it searches those records you submitted and returns the results.
This is obviously a ton more work on my end. However, the neat thing about doing search this way is that I have more control over how relevance is determined for search results and how they are displayed. There are four different kinds of attributes for the search records: searching, displaying, filtering, and customizing ranking. For more relevant results, Algolia recommends creating a new record for each section of a page. They suggest breaking up by paragraph, for example.
I have been able to use GraphQL to generate a JSON syntax tree of each of the MDX content pages that are part of the site. I am currently studying up on the mds-js specification, mdAST specification, uniST specification, syntax trees, and the tools available to me to walk through them so that I can go through each page and create all the records I need to submit to Algolia.
One of my dependencies, Material-UI, uses this search engine. I liked how they were able to format their results and also how quickly it ran. I hope to reproduce something near that level once I am done with my own implementation.
Since this is a static site generator, I need to use or create a service to do the searching for me. Otherwise, the user would need to download the text of every page in the site when they use search.
I started looking at a bunch of different engines and decided on Algolia. It is unique, from what I can tell, in that it doesn't index your site via a site crawler. Instead, you create JSON objects of all your possible search records and send it to their servers. Then, when you call their search service, it searches those records you submitted and returns the results.
This is obviously a ton more work on my end. However, the neat thing about doing search this way is that I have more control over how relevance is determined for search results and how they are displayed. There are four different kinds of attributes for the search records: searching, displaying, filtering, and customizing ranking. For more relevant results, Algolia recommends creating a new record for each section of a page. They suggest breaking up by paragraph, for example.
I have been able to use GraphQL to generate a JSON syntax tree of each of the MDX content pages that are part of the site. I am currently studying up on the mds-js specification, mdAST specification, uniST specification, syntax trees, and the tools available to me to walk through them so that I can go through each page and create all the records I need to submit to Algolia.
One of my dependencies, Material-UI, uses this search engine. I liked how they were able to format their results and also how quickly it ran. I hope to reproduce something near that level once I am done with my own implementation.
For anyone interested in learning or relearning algorithms, check out Algorithms Part I and II from Princeton University on coursera. They're completely free but sadly don't offer a certificate.
https://www.coursera.org/learn/algorithms-part1
https://www.coursera.org/learn/algorithms-part2
https://www.coursera.org/learn/algorithms-part1
https://www.coursera.org/learn/algorithms-part2
Noone should have any interest in relearning algorithms. We only learn them for fucking job interviews.
It could be somewhat useful if you are doing lower level stuff. But the real thing to learn at that point is how to measure how efficient your algorithms are and how to prove that they work. In which case, going more academic and learning maths at a university or something would be more helpful.
I have had several of Knuth's Art of Computer Science books for over a decade now that do a pretty good job of this and I still haven't made it past halfway through the first book because fuck proofs.
I have had several of Knuth's Art of Computer Science books for over a decade now that do a pretty good job of this and I still haven't made it past halfway through the first book because fuck proofs.
By reilo Go To PostNoone should have any interest in relearning algorithms. We only learn them for fucking job interviews.I have to fuck with algorithms far far too often