Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

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

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 the average 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 the users.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 or defn- 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 more let 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 of lumo.




  • 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


img


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 do lein repl and it'll land you in the innovation_competition.core namespace. Feel free to play around smiley




  • 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


img


Once the REPL fires up, you can confirm the namespace you can use *ns*


img



  • Spacemacs
    $$ Just open the core.clj and press ,' and you'd jack in right into the innovation_competition.core namespace


img


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.


img


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 and clojurescript repl. Think of it as a much better version of jupyter 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 frowning