データストラクチャー Arrays
Data Structure Array
Static arrayとDynamic arrayがある。Jsなどのhigh level languageでは特に意識することないが、low level languageなどでは気にする必要がある。
JavaでいうArray
はstatic / ArrayList
はdynamicにあたる。
ArraysのBigO
Static | Dynamic | Big O |
---|---|---|
lookup | lookup | O(1) |
push | append | O(1) |
insert | insert | O(n) |
delete | delete | O(n) |
※appendはO(n)になり得る。
Ex)
const string = ['a', 'b', 'c', 'd', 'e']; // 4 * 4 の16bytesのstorage strings.push('e'); // O(1) strings.push(); // O(1) strings.unshift('x'); // O(n) strings.splice(2, 0, 'e'); // O(n)
unshiftとspliceがO(n)になる理由は、値が配列の先頭または指定箇所に代入されることによって、 それまでのindexの位置がループによって書き換えられるため。
class MyArray{ constructor() { this.length = 0; this.data = {}; } get(index) { return this.data[index]; } push(item) { this.data[this.length] = item; this.length++; return this.length; } pop(){ const lastItem = this.data[this.length -1]; delete this.data[this.length-1]; this.length--; return lastItem; } delete(index) { const item = this.data[index]; this.shuftItems(index); return item; } shuftItems(index) { for(let i = index; i < this.length -1; i++){ this.data[i] = this.data[i+1]; } delete this.data[this.length-1]; this.length--; } } const newArray = new MyArray(); newArray.push('hi'); newArray.push('world'); newArray.pop(); console.log(newArray);
Ex1) Reverse String
const reverseString = (string) => { let arr = string.split(""); let reverseArr = []; for(let i = 0; i < arr.length; i++){ reverseArr.unshift(arr[i]); } console.log(reverseArr.join('')) } reverseString("apple is good"); const reverseString2 = (string) => { // check input if(!string || string.length < 2 || typeof string !== 'string') { return "that is not good"; } const backwords = []; const totalItems = string.length - 1; for(let i = totalItems; i >= 0; i--){ backwords.push(string[i]); } return backwords.join(''); } const reverseString3 = (str) => { return str.split('').reverse().join(); } const reverseString4 = (str) => str.split('').reverse().join(); const reverseString5 = str => [...str].reverse().join(); console.log(reverseString2("banana is soso"));
Data Structureの問題を解く際に、inputのチェックをすることが大事。
EX2) MergeSortedArray
mergeSortedArrays([0,3,4,31], [4,6,30]); const mergeSortedArrays = (arr1, arr2) => { const arr = arr1.concat(arr2); arr.sort((a, b) => a-b); console.log(arr.join(',')); } const mergeSortedArrays1 = (arr1, arr2) => { const mergedArray = []; let array1Item = arr1[0]; let array2Item = arr2[0]; let i = 1; let j = 1; // check input if(arr1.length === 0) { return arr2; } if(arr2.length === 0){ return arr1; } while(array1Item || array2Item) { if(!array2Item || array1Item < array2Item) { mergedArray.push(array1Item); array1Item = arr1[i]; i++; } else { mergedArray.push(array2Item); array2Item = arr2[j]; j++; } } return mergedArray; } console.log(mergeSortedArrays1([0,3,4,31], [4,6,30]));
ArraysのProsとCons
Pros | Cons |
---|---|
Fast lookups | Slow Inserts |
Fast push/pop | Slow deletes |
Ordered | Fixed size* |
*static Arrayを使う場合
React-Reduxアプリケーション開発入門まとめ
概要
こんにちはtogashoです。
今回はフロントエンドエンジニアのためのReact・Reduxアプリケーション開発入門の基礎編で学んだReactとReduxの基本的なところを自分の忘備録も兼ねてをまとめてみました。
React
Facebook社が開発したライブラリー
- DOMの変更箇所だけをレンダリングする
- DOMの変更箇所がどこかを開発者が気にする必要がない
JSX
javascript XMLの略。
JSXの利点とは
jsでも表示できるが、JSXの方が直感的にコーディングでき可読性が高い。
文法
- JSXが使われているときは
react
をimportする必要がある。JSXを使わなければreact
は必要ない。 {}
の中では、jsが実行できる。- classはclassNameと定義する。
- 属性名はキャメルケースで定義する。
onClick
やonChange
など - returnで複数の要素を返す場合、divタグで囲む。
Fragment
はdivタグで囲むのと同じ役割をするが、ブラウザ上では表示されない。
トランスパイル
JSXを実行可能なjsに変換すること。Babelが暗黙的にやっている。
Webpack
モジュールバンドラー。ソースコードを束ねて、一つのファイルにまとめて定義し、ブラウザで表示する。
コンポーネント
関数の定義によるものとクラス定義によるものがある。
// 関数定義 import React from 'react' const Register = () => { return ( <div> </div> ) } export default Register
//クラス定義 import React, { Component } from 'react' export default class Register extends Component { render() { return ( <div> </div> ) } }
props
- コンポーネントの属性の名前。{}で囲って値を渡す。親から子にデータを渡す。
- immutable(変更不可能)な値
//ex) import React from 'react' const App = () => { const profiles = [ {name: "Taro", age: 18}, {name: "Sam", age: 21}, {name: "Bob"}, ] return ( <div> { // コンポーネントにpropsを渡す profiles.map((profile, index) => { return <User name={profile.name} age={profile.age} key={index} /> }) } </div> ) } // 親から渡されたpropsを引数として受け取る。 const User = (props) => { return ( <div>Hi, I am {props.name}, and {props.age} years old!</div> ) } // デフォルトのpropsの設定 User.defaultProps = { age: 1 } export default App
prop-types
- propertiesに対する型のチェックをするためのパッケージ。
import Proptypes from 'prop-types'
でimportするisRequired
で必須にできる。- コンポーネントを設計する段階で、受け取るプロパティの型がぶれないように設計することが大事
//ex) User.propTypes = { name: Proptypes.strng, age: Proptypes.number }
State
- コンポーネントの中で状態を保つこと。コンポーネント内部でしか使えない
- mutable(変更可能)な値
this.state
でアクセスできるthis.setState
で状態を変える。setStateが実行されるとそのコールバックでrenderが再実行される
import React, { Component, Fragment } from 'react'; const App = () => (<Counter></Counter>); class Counter extends Component { // constructorはcomponentの初期化時に呼ばれるコールバック constructor(props){ super(props) this.state = { count: 0} } handlePlusButton(){ this.setState({count: this.state.count +1 }) } handleMinusButton(){ this.setState({count: this.state.count - 1 }) } render() { return ( <Fragment> <div>count: {this.state.count}</div> <button onClick={this.handlePlusButton}>+1</button> <button onClick={this.handleMinusButton}>-1</button> </Fragment> ) } } export default App;
Reduxの概要
コンポーネントの階層が大きくなった時に、容易に状態を共有する手段を提供する。
action
- アプリケーションの中で何が起きたかを示すデータ。jsオブジェクトのこと。
- typeというキー(ユニークでなけれならない)とタイプに対応する値を持つ。
action creator
- actionを定義して、それを返す関数のことをaction creatorと呼ぶ
- typeで指定した値は、reducerでも使う。
- viewを担当するコンポーネントがactionをimportして、あるイベントを掴んだ時に当該のaction creatorをinvokeして適切な状態遷移を実行させるための仕組み。
export const INCREMENT = 'INCREMENT'; export const DECREMENT = 'DECREMENT'; // action creator export const increment = () => ({ type: INCREMENT }) export const decrement = () => ({ type: DECREMENT })
Reducer
- actionが発生した時に、そのアクションに組み込まれているtypeに応じて状態をどのように変化させるのかを定義するもの
- 状態は、コードの中ではstateという名称で扱う。
- アプリケーションの事実上の状態を持つreducerを定義する。
// index.js // アプリケーション内に存在する全てのreducerを総括する。全てのreducerを結合する。 //combineReducersがreducerを結合する import { combineReducers} from 'redux'; import count from './count'; export default combineReducers({ count });
// counter.js // actionをimportする import { INCREMENT, DECREMENT} from '../actions/index'; //状態をの初期値を定義する const initialState = { value: 0 } // actionのtypeを受け取り、switch文で状態をどう変化させるのかを定義する。 export default (state = initialState, action) => { switch (action.type){ case INCREMENT: return { value: state.value + 1} case DECREMENT: return { value: state.value - 1} default: return state } }
Store
- reducerをもとにstoreを作成する。そのstoreが全てのアプリケーション内で使えるようにする。
createStore()
で行う。 - storeを全コンポーネントを参照できるようにするため、
Provider
がreact-redux
から提供されている。
import React from 'react'; import ReactDOM from 'react-dom'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import App from './components/App'; import './index.css'; import reducer from './reducers'; // アプリケーション内の全てのstateはこのstateに集約されている const store = createStore(reducer) // 既存のcomponentをProviderでラッピングする ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
connectでstateとactionsとの関連づけ
- react-reduxが提供するconnect関数を使用して、stateやactionをコンポーネントに紐づける。viewのイベントで状態を遷移させ、遷移後の状態を再renderingする。
mapStateToProps
はstateの情報からこのコンポーネントで必要な物を取り出して、コンポーネント内のpropsとしてmappingする機能を持つ関数。引数には状態のtopレベルを表すstateを渡して、どういったオブジェクトをpropsに対応させるのかを関数の戻り値として定義する。mapDispatchToProps
あるアクションが発生した時にreducerにtypeに応じた状態遷移を実行させる関数がdispatch。dispatch関数を引数において、このコンポーネントに必要となるdispatch関数を宣言する。
import React, { Component, Fragment } from 'react'; import { connect } from 'react-redux'; // action creatorを呼び出す。 import { increment, decrement } from '../actions'; class App extends Component { render() { const props = this.props; return ( <Fragment> <div>value: { props.value }</div> <button onClick={props.increment}>+1</button> <button onClick={props.decrement}>-1</button> </Fragment> ) } } // stateとcomponentを関連づける const mapStateToProps = state => ({value: state.count.value}); const mapDispatchToProps = ({increment, decrement}); // 下記でも可 // const mapDispatchToProps = dispatch => ({ // increment: () => dispatch(increment()), // decrement: () => dispatch(decrement()) //}) // connectの引数にmapStateToPropsとmapDispatchToProps渡してAppに紐付ける。 export default connect(mapStateToProps, mapDispatchToProps)(App);
ご一読いただきありがとうございました。指摘事項等ございましたら、ご指摘いただけると幸いです。
天気予報アプリ(express無し)の実装
はじめに
はじめたのブログ投稿になります。現在、海外でwebエンジニアになるべくカナダのバンクーバのカレッジに通っています。勉強した内容や、カナダでの生活を記事にしていこうと思いますので、どうぞよろしくお願いいたします。
概略
この記事ではUdemyのThe Complete Node.js Developer Course(3rd Edition)のSection6~9の内容を簡単にまとめました。
ここでは、APIを取得する方法とjsonで渡された値の取得方法を学びました。
Topic
- Callback関数
- Fetch
- json
- コマンド引数
- module(import/export)
- 分割代入
使用ライブラリ
- request (簡単にhttpを作成するためのライブラリ)
使用API
実装
// app.js // utilsをimport(nodejsはimportではなく、requireでモジュールを取得する) const geocode = require('./utils/geocode'); const forecast = require('./utils/forecast'); // コマンドから渡された引数を格納する const addres = process.argv[2]; // 引数が渡されなかったら、エラーを返す。 if(!address) { return console.log('please provide an address') } // geocodeを実行し、エラーがない場合、latitude,longitude,loactionを取得し、forecastに値を渡す。 geocode(address, (error, {latitude, longitude, location})=> { if(error){ return console.log(error); } // geocodeから渡された、latitudeとlongitudeをもとに天気予報と降水確率を返す。 forecast(latitude, longitude, (error, forecastData)=>{ if(error) { return console.log(error); } console.log(location); console.log(forecastData); }) })
// geocode.js const request = require('request') // importしたgeocode()を呼び出す。addressにはコマンド引数が渡される。 const geocode = (address, callback) => { //mapboxをfetchする。 const url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/'+ encodeURIComponent(address) + '.json?access_token=pk.eyJ1IjoidGd3IiwiYSI6ImNqdXBsN3ZlOTNiM3k0M252MzA1ZzY2NTkifQ.ucwg_oXHd7KDVTHgSufvTQ'; // urlが正しく、json型で返されているかを判定する。 request({url: url, json: true}, (error,{body})=>{ // Urlが不正な場合、errorを返す if(error){ callback('Unable to connect location service', undefined); // body.featuresに値がない場合、エラーを返す } else if(body.features.length === 0) { callback('unable to find your location', undefined); // 正常に値が返ってきた場合、latitude, longitude, locationを返す } else { callback(undifined, { latitude: body.features[0].center[1]; longitude: body.feature[0].center[0], location: body.features[0].place_name }) } }) }
// forecast.js const request = require('request') const forecast = (latitude, longitude, callback) => { const url = `https://api.darksky.net/forecast/cc390e4b8d3d1951f092c99243ae915d/${latitude},${longitude}?units=si`; //渡されたurlが正しく、json型で返ってきた場合、天気予報と降水確率を返す。 request({url, json: true},(error, { body })=>{ if(error) { callback('unable to connect service', undefined);) } else if (body.error) { callback('unable to find location', undefined) } else { callback(undefined, `${body.daily.summary}, ${body.daily.data[0].precipProbablity}%`) } }) } module.exports = forecast;
mapbox api (ここではcenterの緯度経緯度を取得)
features: [ { id: "place.9391334652012190", type: "Feature", place_type: [ "place" ], relevance: 1, properties: { wikidata: "Q100" }, text: "Boston", place_name: "Boston, Massachusetts, United States", bbox: [ -71.1255750165112, 42.3196059806256, -70.9860500028801, 42.3974009328397 ], center: [ -71.0596, 42.3605 ], geometry: { type: "Point", coordinates: [ -71.0596, 42.3605 ] }, context: [ { id: "region.6776276020561540", short_code: "US-MA", wikidata: "Q771", text: "Massachusetts" }, { id: "country.9053006287256050", short_code: "us", wikidata: "Q30", text: "United States" } ] },
darksky api (mapboxから取得した緯度経度をもとにdaily.sammaryとdaily.data[0]. precipProbabilityを取得)
実際、日々の生活でみるデータのやり取りが、このようなフォーマットで行われています。瞬時にデータのやり取りをするコンピュータはすごいですね!
{ latitude: 42.3605, longitude: -71.0596, timezone: "America/New_York", currently: { time: 1556073863, summary: "Overcast", icon: "cloudy", nearestStormDistance: 0, precipIntensity: 0, precipProbability: 0, temperature: 7.82, apparentTemperature: 6.93, dewPoint: 6.27, humidity: 0.9, pressure: 1011.35, windSpeed: 1.72, windGust: 2.83, windBearing: 122, cloudCover: 1, uvIndex: 0, visibility: 15.59, ozone: 331.58 }, daily: { summary: "Light rain today through Saturday, with high temperatures rising to 20°C on Sunday.", icon: "rain", data: [ { time: 1555992000, summary: "Overcast throughout the day.", icon: "cloudy", sunriseTime: 1556013117, sunsetTime: 1556062523, moonPhase: 0.65, precipIntensity: 0.3277, precipIntensityMax: 2.3292, precipIntensityMaxTime: 1555995600, precipProbability: 1, precipType: "rain", temperatureHigh: 12.1, temperatureHighTime: 1556038800, temperatureLow: 7.68, temperatureLowTime: 1556071200, apparentTemperatureHigh: 12.1, apparentTemperatureHighTime: 1556038800, apparentTemperatureLow: 6.71, apparentTemperatureLowTime: 1556082000, dewPoint: 7.77, humidity: 0.88, pressure: 1013.36, windSpeed: 1.72, windGust: 5.15, windGustTime: 1556024400, windBearing: 43, cloudCover: 1, uvIndex: 4, uvIndexTime: 1556035200, visibility: 11.04, ozone: 332.64, temperatureMin: 7.68, temperatureMinTime: 1556071200, temperatureMax: 12.1, temperatureMaxTime: 1556038800, apparentTemperatureMin: 6.86, apparentTemperatureMinTime: 1556002800, apparentTemperatureMax: 12.1, apparentTemperatureMaxTime: 1556038800 }
終わりに
この記事では、講座の中で紹介されていたexpressを使用しない実装方法を紹介しました。この講座の中では、expressを使って同じapiを叩く実装も紹介されているので、後日紹介できればと思います。
ご指摘いただけることがありましたら、ご指摘いただけると幸いです。お読みいただきありがとうございました。