Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/abhi18av/innovation-competition
Submission for a programming challenge
https://github.com/abhi18av/innovation-competition
clojure clojurescript data-analysis
Last synced: 4 days ago
JSON representation
Submission for a programming challenge
- Host: GitHub
- URL: https://github.com/abhi18av/innovation-competition
- Owner: abhi18av
- License: epl-2.0
- Created: 2019-08-20T10:09:44.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2019-09-02T10:58:50.000Z (over 5 years ago)
- Last Synced: 2024-11-09T19:29:12.224Z (2 months ago)
- Topics: clojure, clojurescript, data-analysis
- Language: HTML
- Homepage:
- Size: 2.32 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.html
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
README.md
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/body {
font-family: "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
font-size: 14px;
padding: 0 12px;
line-height: 22px;
word-wrap: break-word;
}#code-csp-warning {
position: fixed;
top: 0;
right: 0;
color: white;
margin: 16px;
text-align: center;
font-size: 12px;
font-family: sans-serif;
background-color:#444444;
cursor: pointer;
padding: 6px;
box-shadow: 1px 1px 1px rgba(0,0,0,.25);
}#code-csp-warning:hover {
text-decoration: none;
background-color:#007acc;
box-shadow: 2px 2px 2px rgba(0,0,0,.25);
}body.scrollBeyondLastLine {
margin-bottom: calc(100vh - 22px);
}body.showEditorSelection .code-line {
position: relative;
}body.showEditorSelection .code-active-line:before,
body.showEditorSelection .code-line:hover:before {
content: "";
display: block;
position: absolute;
top: 0;
left: -12px;
height: 100%;
}body.showEditorSelection li.code-active-line:before,
body.showEditorSelection li.code-line:hover:before {
left: -30px;
}.vscode-light.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(0, 0, 0, 0.15);
}.vscode-light.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(0, 0, 0, 0.40);
}.vscode-dark.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(255, 255, 255, 0.4);
}.vscode-dark.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(255, 255, 255, 0.60);
}.vscode-high-contrast.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(255, 160, 0, 0.7);
}.vscode-high-contrast.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(255, 160, 0, 1);
}img {
max-width: 100%;
max-height: 100%;
}a {
color: #4080D0;
text-decoration: none;
}a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}h1 {
padding-bottom: 0.3em;
line-height: 1.2;
border-bottom-width: 1px;
border-bottom-style: solid;
}h1, h2, h3 {
font-weight: normal;
}h1 code,
h2 code,
h3 code,
h4 code,
h5 code,
h6 code {
font-size: inherit;
line-height: auto;
}a:hover {
color: #4080D0;
text-decoration: underline;
}table {
border-collapse: collapse;
}table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}table > thead > tr > th,
table > thead > tr > td,
table > tbody > tr > th,
table > tbody > tr > td {
padding: 5px 10px;
}table > tbody > tr + tr > td {
border-top: 1px solid;
}blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left: 5px solid;
}code {
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
font-size: 14px;
line-height: 19px;
}body.wordWrap pre {
white-space: pre-wrap;
}.mac code {
font-size: 12px;
line-height: 18px;
}pre:not(.hljs),
pre.hljs code > div {
padding: 16px;
border-radius: 3px;
overflow: auto;
}/** Theming */
.vscode-light,
.vscode-light pre code {
color: rgb(30, 30, 30);
}.vscode-dark,
.vscode-dark pre code {
color: #DDD;
}.vscode-high-contrast,
.vscode-high-contrast pre code {
color: white;
}.vscode-light code {
color: #A31515;
}.vscode-dark code {
color: #D7BA7D;
}.vscode-light pre:not(.hljs),
.vscode-light code > div {
background-color: rgba(220, 220, 220, 0.4);
}.vscode-dark pre:not(.hljs),
.vscode-dark code > div {
background-color: rgba(10, 10, 10, 0.4);
}.vscode-high-contrast pre:not(.hljs),
.vscode-high-contrast code > div {
background-color: rgb(0, 0, 0);
}.vscode-high-contrast h1 {
border-color: rgb(0, 0, 0);
}.vscode-light table > thead > tr > th {
border-color: rgba(0, 0, 0, 0.69);
}.vscode-dark table > thead > tr > th {
border-color: rgba(255, 255, 255, 0.69);
}.vscode-light h1,
.vscode-light hr,
.vscode-light table > tbody > tr + tr > td {
border-color: rgba(0, 0, 0, 0.18);
}.vscode-dark h1,
.vscode-dark hr,
.vscode-dark table > tbody > tr + tr > td {
border-color: rgba(255, 255, 255, 0.18);
}.vscode-light blockquote,
.vscode-dark blockquote {
background: rgba(127, 127, 127, 0.1);
border-color: rgba(0, 122, 204, 0.5);
}.vscode-high-contrast blockquote {
background: transparent;
border-color: #fff;
}/* Tomorrow Theme */
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Original theme - https://github.com/chriskempson/tomorrow-theme *//* Tomorrow Comment */
.hljs-comment,
.hljs-quote {
color: #8e908c;
}/* Tomorrow Red */
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion {
color: #c82829;
}/* Tomorrow Orange */
.hljs-number,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params,
.hljs-meta,
.hljs-link {
color: #f5871f;
}/* Tomorrow Yellow */
.hljs-attribute {
color: #eab700;
}/* Tomorrow Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-addition {
color: #718c00;
}/* Tomorrow Blue */
.hljs-title,
.hljs-section {
color: #4271ae;
}/* Tomorrow Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #8959a8;
}.hljs {
display: block;
overflow-x: auto;
color: #4d4d4c;
padding: 0.5em;
}.hljs-emphasis {
font-style: italic;
}.hljs-strong {
font-weight: bold;
}/*
* Markdown PDF CSS
*/body {
font-family: "Meiryo", "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
}pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
border-radius: 3px;
overflow-x: auto;
white-space: pre-wrap;
overflow-wrap: break-word;
}pre:not(.hljs) {
padding: 23px;
line-height: 19px;
}blockquote {
background: rgba(127, 127, 127, 0.1);
border-color: rgba(0, 122, 204, 0.5);
}.emoji {
height: 1.4em;
}/* for inline code */
:not(pre):not(.hljs) > code {
color: #C9AE75; /* Change the old color so it seems less like an error */
font-size: inherit;
}/* Page Break : use <div class="page"/> to insert page break
-------------------------------------------------------- */
.page {
page-break-after: always;
}Problem Statement: Nosco Hiring Challenge
There is an innovation competition across the land, and the various
houses compete. All the ideas have been collected and scored, and now is the time
to calculate the results to find out the most innovative houses.
-
The
innovation score
of a house is simply theaverage scores
of all the ideas
submitted by people affiliated with this house. -
Higher is better.
-
Ideas with no scores are excluded from consideration.
-
Some people are affiliated with no house, in which case they should be counted as if in the house 'Free folk'.
-
Some people are affiliated with more than one house, in which case the idea is credited to each and every one of the affiliated houses. For example, if user A is affiliated with houses X and Y, and they have submitted an idea that has a score of 5.7, both house X and Y will add a score of 5.7 in their tally.
Input Data
The input data is two JSON files, and their EDN counterparts (containing the same data).
-
users.json
contains various users, each having an id first name, last name, email, and potentially a list of their house affiliation(s). -
ideas.json
contains various ideas, each one having an id, a title, a body, an author-id (pointing to one entry in theusers.json
file) and an array of numeric scores. Unfortunately some scores were lost and were replaced by nulls. These scores should be ignored entirely.
Expected output
The results should include:
an list of the houses, from most innovative to least innovative
the innovation score of each house
the number of ideas submitted by each house
Other considerations
Reasonable performance is expected, but readability of the code is more
important. Use descriptive names and add docstrings and comments as needed.
You're free to use any 3rd-party library that seems suitable for the
task, keeping in mind how it might affecte the readability of the code for someone
who isn't familiar with it.
The code should include instructions on how to run it and get the results.
Any reasonably popular build tool is fine, or a single file with
side-effectful statements will also do. Use the tool that will allow
you to move to actually solving the problem.
There's no need to write a test suite for this exercise.
Solution by Abhinav Sharma ([email protected])
Design Considerations
-
Could have used
:^private
ordefn-
if this was a library oriented solution. However, as mentioned in the challenge description I've optimized for readibility rather than less number variables or morelet
bindings along with other deep clojure constructs. This would be caliberated as per the team standard. -
Opted to deliver the base solution in the a single
lumo.cljs
file so as to avoid the hassle of setting up a build configs and slow startups. -
I have only used the
clojure standard library
since, it's already there and I wanted the code to be usable by vanilla installation oflumo
. -
Didn't use
spec
at all. -
Depending on the team's comfort level, standard and design choices, I might have opted for specter or medley to simplify things
Thoughts
-
A shared resource pool would be really helpful like Clojure - The Essential Reference or PurelyFunctional courses. This way, as a team we could be sure of each other's miminal knowledge base.
-
In production for nested queries, I think it might be worth trying out pathom pathom for traversing nested queries.
Solution-1: ClojureScript (via Lumo on Terminal)
Instructions to download and setup lumo
Lumo bundles ClojureScript
and NodeJS
together as a single binary. More info can be found at https://github.com/anmonteiro/lumo.
I've used it in the past to create the classic snake game using the browser's canvas
API - luminus-snake
The core solution is based around a single file ./src/innovation_competition/lumo.cljs
which is intended to be used as follows
> cd ./src/innovation_competition/
> lumo lumo.cljs
The solution would be printed out as like so
You could also just compile the lumo.cljs
solution to NodeJS
ready solution by using the bundled clojurescript compiler like done here luminus-snake/build_snake.cljs
Solution-2: Clojure (via REPLs)
The ./src/innovation_competition/core.clj
file is the file which is meant to be used with a REPL
as it contains commented code-snippets which could be used to explore the state of variables and the functionality of functions.
-
Terminal REPL
The simplest way to start a repl would be to dolein repl
and it'll land you in theinnovation_competition.core
namespace. Feel free to play around -
Cursive via IntelliJ
You'll need to open the project in the IntelliJ
iwth Curisive
plugin installed and the config the local nrepl like so
Once the REPL
fires up, you can confirm the namespace you can use *ns*
- Spacemacs
$$ Just open thecore.clj
and press,'
and you'djack in
right into theinnovation_competition.core
namespace
Solution-3: Python (via Jupyter)
This was a really fun problem to work with and I explored the solution using another tool I have, which is Python
and so you can find the HTML
or the Jupyter Notebook
in the ./python
directory.
Feedback
-
It was a wonderfully refreshing test and this ability of clojurians to try new things is the reason why I am so fond of clojure and it's community.
-
To avoid the multiple build tools you might need to install to evaluate various other submissions, you could ask people to use nextjournal as it comes with an in-built
clojure
andclojurescript
repl. Think of it as a much better version ofjupyter notebooks
.
Things I tried
-
Adding rebel-readline library to the project to make the
lein repl
colorful but decided against adding another dependency. -
Exploring the data via cognitect's REBL, couldn't make it work